├── .env
├── .gitignore
├── .travis.yml
├── CONTRIBUTING.rst
├── LICENSE
├── MANIFEST.in
├── README.md
├── assets
├── index.html
└── video
│ └── rtcontrol-curses.ogg
├── bootstrap.sh
├── debian
├── changelog
└── control
├── docs
├── Makefile
├── SUPPORT.rst
├── _static
│ ├── css
│ │ └── custom.css
│ ├── img
│ │ ├── favicon.ico
│ │ ├── help.png
│ │ ├── logo-75.png
│ │ ├── logo-wide.svg
│ │ ├── logo.png
│ │ └── logo.svg
│ └── js
│ │ └── custom.js
├── advanced-monitoring.rst
├── advanced-queue.rst
├── advanced-rtcontrol.rst
├── advanced-rtxmlrpc.rst
├── advanced-tree-watch.rst
├── advanced.rst
├── api.rst
├── apidoc
│ ├── pyrocore.daemon.rst
│ ├── pyrocore.rst
│ ├── pyrocore.scripts.rst
│ ├── pyrocore.torrent.rst
│ ├── pyrocore.ui.rst
│ ├── pyrocore.util.rst
│ └── tempita.rst
├── conf.py
├── contributing.rst
├── custom-fields.rst
├── custom-jobs.rst
├── custom-scripts.rst
├── custom.rst
├── examples
│ ├── conky-rtorstat.png
│ ├── ratio_histo.png
│ ├── rt-backseat
│ ├── rt-down-stats.py
│ ├── rt-heatmap.py
│ ├── rt-stuck-trackers.py
│ ├── rt_cron_throttle_seed
│ ├── rtcontrol-colors.png
│ ├── rtorrent-ex.png
│ ├── rtorrent.rc
│ ├── rtorstat.png
│ ├── rtuptime
│ ├── start.sh
│ └── tmux.conf
├── experimental.rst
├── howto.rst
├── include-api-uml.rst
├── include-contacts.rst
├── include-xmlrpc-dialects.rst
├── index.rst
├── installation.rst
├── license.rst
├── overview.rst
├── references-cli-usage.rst
├── references.rst
├── requirements.txt
├── setup.rst
├── tempita.rst
├── troubleshooting.rst
├── updating.rst
├── usage-cli-tools.rst
├── usage-rtcontrol.rst
├── usage-std-config.rst
├── usage-templates.rst
├── usage.rst
└── videos
│ ├── bash-completion.gif
│ └── rtcontrol-curses.gif
├── pavement.py
├── paver-minilib.zip
├── pylint.cfg
├── requirements-dev.txt
├── requirements-torque.txt
├── requirements.txt
├── setup.cfg
├── setup.py
├── src
├── pyrocore
│ ├── __init__.py
│ ├── config.py
│ ├── daemon
│ │ ├── __init__.py
│ │ └── webapp.py
│ ├── data
│ │ ├── config
│ │ │ ├── bash-completion
│ │ │ ├── color-schemes
│ │ │ │ ├── default-16.rc
│ │ │ │ ├── default-256.rc
│ │ │ │ ├── default-8.rc
│ │ │ │ ├── happy-pastel.rc
│ │ │ │ ├── solarized-blue.rc
│ │ │ │ └── solarized-yellow.rc
│ │ │ ├── config.ini
│ │ │ ├── config.py
│ │ │ ├── logging.cron.ini
│ │ │ ├── logging.scripts.ini
│ │ │ ├── logging.torque.ini
│ │ │ ├── rtorrent-pyro.rc
│ │ │ ├── rtorrent.d
│ │ │ │ ├── 00-default.rc
│ │ │ │ ├── auto-scrape.rc
│ │ │ │ ├── bind-navigation-keys.rc
│ │ │ │ ├── categories.rc
│ │ │ │ ├── collapse-built-in-views.rc
│ │ │ │ ├── commands.rc
│ │ │ │ ├── helper-methods.rc
│ │ │ │ ├── logging.rc
│ │ │ │ ├── quick-help.rc
│ │ │ │ ├── theming.rc
│ │ │ │ ├── timestamps.rc
│ │ │ │ ├── torque.rc
│ │ │ │ ├── view-datasize.rc
│ │ │ │ ├── view-indemand.rc
│ │ │ │ ├── view-last_xfer.rc
│ │ │ │ ├── view-messages.rc
│ │ │ │ ├── view-ratio.rc
│ │ │ │ ├── view-tagged.rc
│ │ │ │ ├── view-trackers.rc
│ │ │ │ └── view-uploaded.rc
│ │ │ ├── templates
│ │ │ │ ├── conky
│ │ │ │ │ ├── conkyrc
│ │ │ │ │ └── rtorstat.txt
│ │ │ │ ├── irc_status.txt
│ │ │ │ ├── json
│ │ │ │ ├── orphans.txt
│ │ │ │ ├── rss.xml
│ │ │ │ └── rtorstat.html
│ │ │ └── torque.ini
│ │ ├── htdocs
│ │ │ ├── css
│ │ │ │ ├── custom.css
│ │ │ │ └── style.css
│ │ │ ├── favicon.ico
│ │ │ ├── img
│ │ │ │ └── pyroscope.png
│ │ │ ├── index.html
│ │ │ └── js
│ │ │ │ └── charts.js
│ │ ├── img
│ │ │ └── rt-logo.png
│ │ └── screenlet
│ │ │ ├── icon.png
│ │ │ └── themes
│ │ │ ├── blueish
│ │ │ └── theme.conf
│ │ │ └── default
│ │ │ └── theme.conf
│ ├── error.py
│ ├── scripts
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── chtor.py
│ │ ├── hashcheck.py
│ │ ├── lstor.py
│ │ ├── mktor.py
│ │ ├── pyroadmin.py
│ │ ├── pyrotorque.py
│ │ ├── rtcontrol.py
│ │ ├── rtevent.py
│ │ ├── rtmv.py
│ │ ├── rtsweep.py
│ │ └── rtxmlrpc.py
│ ├── torrent
│ │ ├── __init__.py
│ │ ├── broom.py
│ │ ├── engine.py
│ │ ├── filter.py
│ │ ├── formatting.py
│ │ ├── jobs.py
│ │ ├── queue.py
│ │ ├── rtorrent.py
│ │ └── watch.py
│ ├── ui
│ │ ├── __init__.py
│ │ ├── categories.py
│ │ └── theming.py
│ └── util
│ │ ├── __init__.py
│ │ ├── algo.py
│ │ ├── load_config.py
│ │ ├── matching.py
│ │ ├── metafile.py
│ │ ├── osmagic.py
│ │ ├── pymagic.py
│ │ ├── stats.py
│ │ ├── traits.py
│ │ └── xmlrpc.py
├── scripts
│ ├── add-categories.sh
│ ├── make-rtorrent-config.sh
│ ├── migrate_rtorrent_rc.sh
│ └── rt09x-command-names.sed
└── tests
│ ├── __init__.py
│ ├── fifotest.sh
│ ├── logging.cfg
│ ├── private.torrent
│ ├── test.torrent
│ ├── test_algo.py
│ ├── test_config.py
│ ├── test_engine.py
│ ├── test_flexget.py
│ ├── test_formatting.py
│ ├── test_matching.py
│ ├── test_metafile.py
│ ├── test_osmagic.py
│ ├── test_pymagic.py
│ ├── test_rtorrent.py
│ ├── test_traits.py
│ └── test_xmlrpc.py
├── update-to-head.sh
└── util.sh
/.env:
--------------------------------------------------------------------------------
1 | # autoenv activation
2 | if [[ -f bin/activate ]]; then . bin/activate; fi
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 |
5 | # C extensions
6 | *.so
7 |
8 | # Distribution / packaging
9 | .Python
10 | env/
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | lib/
17 | lib64/
18 | parts/
19 | sdist/
20 | var/
21 | *.egg-info/
22 | .installed.cfg
23 | *.egg
24 |
25 | # PyInstaller
26 | # Usually these files are written by a python script from a template
27 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
28 | *.manifest
29 | *.spec
30 |
31 | # Installer logs
32 | pip-log.txt
33 | pip-delete-this-directory.txt
34 |
35 | # Unit test / coverage reports
36 | htmlcov/
37 | .tox/
38 | .coverage
39 | .cache
40 | nosetests.xml
41 | coverage.xml
42 |
43 | # Translations
44 | *.mo
45 | *.pot
46 |
47 | # Django stuff:
48 | *.log
49 |
50 | # Sphinx documentation
51 | docs/_build/
52 |
53 | # PyBuilder
54 | target/
55 |
56 | # Subprojects
57 | auvyon/
58 | pyrobase/
59 |
60 | # virtualenv
61 | bin/
62 | include/
63 | local/
64 | man/
65 | share/
66 |
67 | wiki/
68 | pip-selfcheck.json
69 | docs/uml_images/
70 | docs/apidocs/
71 | EGG-INFO/
72 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # https://docs.travis-ci.com/user/customizing-the-build/
3 | language: python
4 | python:
5 | - "2.7"
6 | #before_install:
7 | # - sudo apt-get update -qq
8 | # - sudo apt-get install -qq python-apt python-pycurl
9 | install:
10 | - pip install -U pip
11 | - pip install -U setuptools
12 | - pip install -U wheel
13 | - pip install -r requirements-dev.txt
14 | - pip install -e .[templates,repl]
15 | script:
16 | - paver test
17 | - paver functest
18 | - paver installtest
19 |
20 | # gitter.im
21 | notifications:
22 | webhooks:
23 | urls:
24 | - https://webhooks.gitter.im/e/f8b72e277648046791cf
25 | on_success: change # options: [always|never|change] default: always
26 | on_failure: always # options: [always|never|change] default: always
27 | on_start: never # options: [always|never|change] default: always
28 |
--------------------------------------------------------------------------------
/CONTRIBUTING.rst:
--------------------------------------------------------------------------------
1 | Contributing Guidelines
2 | =======================
3 |
4 | See `contribution-guide.org`_ for the basics on contributing
5 | to an open source project.
6 |
7 |
8 | .. _issue-reporting:
9 |
10 | Reporting an Issue, or Requesting a Feature
11 | -------------------------------------------
12 |
13 | Any defects and feature requests are managed using GitHub's
14 | *issue tracker*.
15 | If you never opened an issue on GitHub before, consult the
16 | `Mastering Issues`_ guide.
17 |
18 | Before creating a bug report, please read the `Trouble-Shooting Guide`_
19 | and also see ``contribution-guide.org``'s `Submitting Bugs`_.
20 |
21 | .. _`Mastering Issues`: https://guides.github.com/features/issues/
22 | .. _`contribution-guide.org`: http://www.contribution-guide.org/
23 | .. _`Submitting Bugs`: http://www.contribution-guide.org/#submitting-bugs
24 | .. _`Trouble-Shooting Guide`: https://pyrocore.readthedocs.org/en/latest/troubleshooting.html
25 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | # Hints for building the source distribution
2 | # See http://docs.python.org/distutils/sourcedist.html
3 |
4 | include bootstrap.sh update-to-head.sh util.sh
5 | include setup.py requirements*.txt pavement.py paver-minilib.zip
6 | include LICENSE CONTRIBUTING.rst
7 | include .env .gitignore .travis.yml pylint.cfg
8 |
9 | recursive-include debian changelog control
10 |
11 | recursive-include assets *.html
12 | #recursive-include assets/video *.ogg
13 |
14 | recursive-include docs *.rst *.py Makefile requirements.txt
15 | recursive-include docs/_static *.ico *.png
16 | recursive-include docs/examples rt-backseat rt_cron_throttle_seed *.conf *.png *.rc *.sh
17 | #recursive-include docs/videos *.gif
18 |
19 | recursive-include src/tests *.py *.sh *.cfg *.torrent
20 | recursive-include src/scripts *.sh *.sed
21 | recursive-include src/pyrocore/data/config rtorrent-*.rc *.ini *.py bash-completion
22 | recursive-include src/pyrocore/data/config/color-schemes *.rc
23 | recursive-include src/pyrocore/data/config/rtorrent.d *.rc
24 | recursive-include src/pyrocore/data/config/templates *.txt *.html conkyrc json
25 | recursive-include src/pyrocore/data/htdocs *.css *.ico *.png *.html *.js
26 | recursive-include src/pyrocore/data/screenlet *.png *.conf
27 | recursive-include src/pyrocore/data/img *.png
28 |
29 | prune docs/build
30 | prune docs/videos
31 | prune assets/video
32 |
33 | # END of MANIFEST
34 |
--------------------------------------------------------------------------------
/assets/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | |
10 |
13 | Python Torrent Tools
14 | |
15 |
16 | PyroScope is a collection of tools for
17 | the BitTorrent protocol and especially
18 | the rTorrent client.
It offers the following components:
19 |
20 |
21 | - CommandLineTools for automation
22 | of common tasks, like metafile creation
- rTorrent extensions like a queue manager
23 | and statistics
- a modern and versatile rTorrent web interface
24 |
25 |
26 | To get started right away, see the QuickStartGuide.
27 | If you want to get a first impression without installing the software, look at the
28 | ScreenShotGallery. It's also very easy to
29 | WriteYourOwnScripts to automate anything
30 | that the standard commands can't do (also see the API documentation).
31 |
32 | To get in contact and share your experiences with other users of
33 | PyroScope, join the
34 | pyroscope-users
35 | mailing list or the inofficial
36 | #rtorrent
37 | channel.
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/assets/video/rtcontrol-curses.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/assets/video/rtcontrol-curses.ogg
--------------------------------------------------------------------------------
/bootstrap.sh:
--------------------------------------------------------------------------------
1 | # This script has to be sourced in a shell and is thus NOT executable.
2 | #
3 | # Set up project
4 | #
5 | # Copyright (c) 2010-2017 The PyroScope Project
6 | #
7 | # This program is free software; you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation; either version 2 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License along
18 | # with this program; if not, write to the Free Software Foundation, Inc.,
19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 |
21 | SCRIPTNAME="$0"
22 | test "$SCRIPTNAME" != "-bash" -a "$SCRIPTNAME" != "-/bin/bash" || SCRIPTNAME="${BASH_SOURCE[0]}"
23 |
24 | export DEBFULLNAME=pyroscope
25 | export DEBEMAIL=pyroscope.project@gmail.com
26 |
27 | deactivate 2>/dev/null || true
28 | test -z "$PYTHON" -a -x "/usr/bin/python2" && PYTHON="/usr/bin/python2"
29 | test -z "$PYTHON" -a -x "/usr/bin/python" && PYTHON="/usr/bin/python"
30 | test -z "$PYTHON" && PYTHON="python"
31 |
32 | git_projects="pyrobase auvyon"
33 | . ./util.sh || return 1 # load funcs
34 |
35 | # generic bootstrap
36 | test -f ./bin/activate || install_venv --no-site-packages
37 | update_venv ./bin/pip
38 | ln -nfs python ./bin/python-pyrocore
39 | . ./bin/activate || abend "venv activate failed" || return 1
40 |
41 | grep DEBFULLNAME bin/activate >/dev/null || cat >>bin/activate </dev/null \
47 | && "$PROJECT_ROOT"/bin/pip uninstall -y distribute || true
48 |
49 | # tools
50 | pip_install -U "pip"
51 | pip_install -U "setuptools>=38"
52 | pip_install -U "packaging"
53 | pip_install -U "paver>=1.0.5"
54 | ##pip_install -U "nose>=1.0"
55 | ##pip_install -U "coverage>=3.4"
56 | pip_install -U "yolk3k"
57 | ##pip_install -U "PasteScript>=1.7.3"
58 |
59 | # Harmless options (just install them, but ignore errors)
60 | pip_install_opt -U "Tempita>=0.5.1"
61 | pip_install_opt -U "APScheduler>=2.0.2,<3"
62 | pip_install_opt -U "waitress>=0.8.2"
63 | pip_install_opt -U "WebOb>=1.2.3"
64 | ##pip_install_opt -U "psutil>=0.6.1"
65 |
66 | # pyrobase
67 | test ! -d pyrobase || ( builtin cd pyrobase && ../bin/paver -q develop -U)
68 |
69 | # essential tools
70 | test -x ./bin/paver || pip_install -U "paver>=1.0.1"
71 |
72 | # package dependencies (optional)
73 | for pkgreq in "Tempita>=0.5.1" "APScheduler>=2.0.2,<3"; do
74 | pip_install_opt "$pkgreq"
75 | done
76 |
77 | # git dependencies
78 | this_paver="$PWD/bin/paver"
79 | for project in $git_projects; do
80 | if test -f ../$project/setup.py; then
81 | ( builtin cd ../$project && $this_paver -q develop -U )
82 | elif test -f $project/setup.py; then
83 | ( builtin cd $project && $this_paver -q develop -U )
84 | else
85 | abend "Project '$project' is not initialized!"
86 | return 1
87 | fi
88 | done
89 |
90 | # project
91 | ./bin/paver -q develop -U || abend "installing $(basename $(pwd)) into venv failed"
92 | ./bin/paver bootstrap || abend "bootstrapping $(basename $(pwd)) failed"
93 |
--------------------------------------------------------------------------------
/debian/control:
--------------------------------------------------------------------------------
1 | # stub file to make dch work - no .deb packaging yet
2 |
3 | Build-Depends: build-essential, devtools, python-dev
4 |
5 | Depends: python2.5, python-virtualenv
6 |
7 |
--------------------------------------------------------------------------------
/docs/SUPPORT.rst:
--------------------------------------------------------------------------------
1 | How to Get Support Efficiently?
2 | ===============================
3 |
4 | To resolve any problems with or questions about your configuration
5 | and software installation, there are several ways that you should try
6 | from top to bottom:
7 |
8 | #. *Always* look into the “Troubleshooting Guide” of the manual as a first measure,
9 | which is often the fastest way to get back to a working system.
10 | That guide also explains how to efficiently report your problem
11 | when you cannot fix it yourself.
12 | #. To get in contact with other users of `PyroScope`_ projects, join the
13 | `pyroscope-users`_ mailing list or the inofficial ``##rtorrent``
14 | channel on ``irc.freenode.net``.
15 | #. *Do* add problems that are clearly a bug to the issue tracker on GitHub
16 | – however use the support channels above for questions about the documentation
17 | or use of the software.
18 |
19 | .. _`PyroScope`: https://github.com/pyroscope
20 | .. _`pyroscope-users`: http://groups.google.com/group/pyroscope-users
21 | .. _`rTorrent-PS`: https://github.com/pyroscope/rtorrent-ps
22 |
--------------------------------------------------------------------------------
/docs/_static/css/custom.css:
--------------------------------------------------------------------------------
1 | /* Custom Sphinx Styles */
2 | body {
3 | color: #000;
4 | }
5 |
--------------------------------------------------------------------------------
/docs/_static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/docs/_static/img/favicon.ico
--------------------------------------------------------------------------------
/docs/_static/img/help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/docs/_static/img/help.png
--------------------------------------------------------------------------------
/docs/_static/img/logo-75.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/docs/_static/img/logo-75.png
--------------------------------------------------------------------------------
/docs/_static/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/docs/_static/img/logo.png
--------------------------------------------------------------------------------
/docs/_static/js/custom.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function(){
2 | $('dt[id]').each(function() {
3 | $('').
4 | attr('href', '#' + this.id).
5 | attr('title', _('Permalink to this definition')).
6 | appendTo(this);
7 | });
8 | });
9 |
--------------------------------------------------------------------------------
/docs/advanced.rst:
--------------------------------------------------------------------------------
1 | Advanced Features
2 | =================
3 |
4 | .. note::
5 |
6 | Using these features requires some knowledge in the area Linux, Bash,
7 | and Python beyond a novice level, but they enable you to customize
8 | your setup even further and handle very specific use-cases.
9 |
10 |
11 | .. _advanced-rtcontrol:
12 |
13 | Advanced ‘rtcontrol’
14 | --------------------
15 |
16 | .. include:: advanced-rtcontrol.rst
17 |
18 |
19 | .. _RtXmlRpcExamples:
20 |
21 | Using ‘rtxmlrpc’
22 | ----------------
23 |
24 | .. include:: advanced-rtxmlrpc.rst
25 |
26 |
27 | .. _QueueManager:
28 |
29 | rTorrent Queue Manager
30 | ----------------------
31 |
32 | .. include:: advanced-queue.rst
33 |
34 |
35 | .. _tree-watch:
36 |
37 | Using the Tree Watch Job
38 | ------------------------
39 |
40 | .. include:: advanced-tree-watch.rst
41 |
--------------------------------------------------------------------------------
/docs/api.rst:
--------------------------------------------------------------------------------
1 | .. _api:
2 |
3 | API Documentation
4 | =================
5 |
6 | This is the full ``pyrocore`` API documentation, generated from source.
7 |
8 | Packages & Modules
9 | ------------------
10 |
11 | .. toctree::
12 | :maxdepth: 4
13 |
14 | apidoc/pyrocore
15 |
16 | .. include : : include-api-uml.rst
17 |
18 |
19 | Tempita Templating API
20 | ----------------------
21 |
22 | .. toctree::
23 | :maxdepth: 4
24 |
25 | apidoc/tempita
26 |
--------------------------------------------------------------------------------
/docs/apidoc/pyrocore.daemon.rst:
--------------------------------------------------------------------------------
1 | pyrocore.daemon package
2 | =======================
3 |
4 | .. automodule:: pyrocore.daemon
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | pyrocore.daemon.webapp module
13 | -----------------------------
14 |
15 | .. automodule:: pyrocore.daemon.webapp
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/apidoc/pyrocore.rst:
--------------------------------------------------------------------------------
1 | pyrocore package
2 | ================
3 |
4 | .. automodule:: pyrocore
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Subpackages
10 | -----------
11 |
12 | .. toctree::
13 |
14 | pyrocore.daemon
15 | pyrocore.scripts
16 | pyrocore.torrent
17 | pyrocore.ui
18 | pyrocore.util
19 |
20 | Submodules
21 | ----------
22 |
23 | pyrocore.config module
24 | ----------------------
25 |
26 | .. automodule:: pyrocore.config
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | pyrocore.error module
32 | ---------------------
33 |
34 | .. automodule:: pyrocore.error
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
39 |
40 |
--------------------------------------------------------------------------------
/docs/apidoc/pyrocore.scripts.rst:
--------------------------------------------------------------------------------
1 | pyrocore.scripts package
2 | ========================
3 |
4 | .. automodule:: pyrocore.scripts
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | pyrocore.scripts.base module
13 | ----------------------------
14 |
15 | .. automodule:: pyrocore.scripts.base
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | pyrocore.scripts.chtor module
21 | -----------------------------
22 |
23 | .. automodule:: pyrocore.scripts.chtor
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | pyrocore.scripts.hashcheck module
29 | ---------------------------------
30 |
31 | .. automodule:: pyrocore.scripts.hashcheck
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 | pyrocore.scripts.lstor module
37 | -----------------------------
38 |
39 | .. automodule:: pyrocore.scripts.lstor
40 | :members:
41 | :undoc-members:
42 | :show-inheritance:
43 |
44 | pyrocore.scripts.mktor module
45 | -----------------------------
46 |
47 | .. automodule:: pyrocore.scripts.mktor
48 | :members:
49 | :undoc-members:
50 | :show-inheritance:
51 |
52 | pyrocore.scripts.pyroadmin module
53 | ---------------------------------
54 |
55 | .. automodule:: pyrocore.scripts.pyroadmin
56 | :members:
57 | :undoc-members:
58 | :show-inheritance:
59 |
60 | pyrocore.scripts.pyrotorque module
61 | ----------------------------------
62 |
63 | .. automodule:: pyrocore.scripts.pyrotorque
64 | :members:
65 | :undoc-members:
66 | :show-inheritance:
67 |
68 | pyrocore.scripts.rtcontrol module
69 | ---------------------------------
70 |
71 | .. automodule:: pyrocore.scripts.rtcontrol
72 | :members:
73 | :undoc-members:
74 | :show-inheritance:
75 |
76 | pyrocore.scripts.rtevent module
77 | -------------------------------
78 |
79 | .. automodule:: pyrocore.scripts.rtevent
80 | :members:
81 | :undoc-members:
82 | :show-inheritance:
83 |
84 | pyrocore.scripts.rtmv module
85 | ----------------------------
86 |
87 | .. automodule:: pyrocore.scripts.rtmv
88 | :members:
89 | :undoc-members:
90 | :show-inheritance:
91 |
92 | pyrocore.scripts.rtsweep module
93 | -------------------------------
94 |
95 | .. automodule:: pyrocore.scripts.rtsweep
96 | :members:
97 | :undoc-members:
98 | :show-inheritance:
99 |
100 | pyrocore.scripts.rtxmlrpc module
101 | --------------------------------
102 |
103 | .. automodule:: pyrocore.scripts.rtxmlrpc
104 | :members:
105 | :undoc-members:
106 | :show-inheritance:
107 |
108 |
109 |
--------------------------------------------------------------------------------
/docs/apidoc/pyrocore.torrent.rst:
--------------------------------------------------------------------------------
1 | pyrocore.torrent package
2 | ========================
3 |
4 | .. automodule:: pyrocore.torrent
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | pyrocore.torrent.broom module
13 | -----------------------------
14 |
15 | .. automodule:: pyrocore.torrent.broom
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | pyrocore.torrent.engine module
21 | ------------------------------
22 |
23 | .. automodule:: pyrocore.torrent.engine
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | pyrocore.torrent.filter module
29 | ------------------------------
30 |
31 | .. automodule:: pyrocore.torrent.filter
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 | pyrocore.torrent.formatting module
37 | ----------------------------------
38 |
39 | .. automodule:: pyrocore.torrent.formatting
40 | :members:
41 | :undoc-members:
42 | :show-inheritance:
43 |
44 | pyrocore.torrent.jobs module
45 | ----------------------------
46 |
47 | .. automodule:: pyrocore.torrent.jobs
48 | :members:
49 | :undoc-members:
50 | :show-inheritance:
51 |
52 | pyrocore.torrent.queue module
53 | -----------------------------
54 |
55 | .. automodule:: pyrocore.torrent.queue
56 | :members:
57 | :undoc-members:
58 | :show-inheritance:
59 |
60 | pyrocore.torrent.rtorrent module
61 | --------------------------------
62 |
63 | .. automodule:: pyrocore.torrent.rtorrent
64 | :members:
65 | :undoc-members:
66 | :show-inheritance:
67 |
68 | pyrocore.torrent.watch module
69 | -----------------------------
70 |
71 | .. automodule:: pyrocore.torrent.watch
72 | :members:
73 | :undoc-members:
74 | :show-inheritance:
75 |
76 |
77 |
--------------------------------------------------------------------------------
/docs/apidoc/pyrocore.ui.rst:
--------------------------------------------------------------------------------
1 | pyrocore.ui package
2 | ===================
3 |
4 | .. automodule:: pyrocore.ui
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | pyrocore.ui.categories module
13 | -----------------------------
14 |
15 | .. automodule:: pyrocore.ui.categories
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | pyrocore.ui.theming module
21 | --------------------------
22 |
23 | .. automodule:: pyrocore.ui.theming
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 |
29 |
--------------------------------------------------------------------------------
/docs/apidoc/pyrocore.util.rst:
--------------------------------------------------------------------------------
1 | pyrocore.util package
2 | =====================
3 |
4 | .. automodule:: pyrocore.util
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | pyrocore.util.algo module
13 | -------------------------
14 |
15 | .. automodule:: pyrocore.util.algo
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 | pyrocore.util.load\_config module
21 | ---------------------------------
22 |
23 | .. automodule:: pyrocore.util.load_config
24 | :members:
25 | :undoc-members:
26 | :show-inheritance:
27 |
28 | pyrocore.util.matching module
29 | -----------------------------
30 |
31 | .. automodule:: pyrocore.util.matching
32 | :members:
33 | :undoc-members:
34 | :show-inheritance:
35 |
36 | pyrocore.util.metafile module
37 | -----------------------------
38 |
39 | .. automodule:: pyrocore.util.metafile
40 | :members:
41 | :undoc-members:
42 | :show-inheritance:
43 |
44 | pyrocore.util.osmagic module
45 | ----------------------------
46 |
47 | .. automodule:: pyrocore.util.osmagic
48 | :members:
49 | :undoc-members:
50 | :show-inheritance:
51 |
52 | pyrocore.util.pymagic module
53 | ----------------------------
54 |
55 | .. automodule:: pyrocore.util.pymagic
56 | :members:
57 | :undoc-members:
58 | :show-inheritance:
59 |
60 | pyrocore.util.stats module
61 | --------------------------
62 |
63 | .. automodule:: pyrocore.util.stats
64 | :members:
65 | :undoc-members:
66 | :show-inheritance:
67 |
68 | pyrocore.util.traits module
69 | ---------------------------
70 |
71 | .. automodule:: pyrocore.util.traits
72 | :members:
73 | :undoc-members:
74 | :show-inheritance:
75 |
76 | pyrocore.util.xmlrpc module
77 | ---------------------------
78 |
79 | .. automodule:: pyrocore.util.xmlrpc
80 | :members:
81 | :undoc-members:
82 | :show-inheritance:
83 |
84 |
85 |
--------------------------------------------------------------------------------
/docs/apidoc/tempita.rst:
--------------------------------------------------------------------------------
1 | tempita package
2 | ===============
3 |
4 | .. automodule:: tempita
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
8 |
9 | Submodules
10 | ----------
11 |
12 | tempita.compat3 module
13 | ----------------------
14 |
15 | .. automodule:: tempita.compat3
16 | :members:
17 | :undoc-members:
18 | :show-inheritance:
19 |
20 |
21 |
--------------------------------------------------------------------------------
/docs/contributing.rst:
--------------------------------------------------------------------------------
1 | .. Include text from the place where GitHub sees it.
2 | .. include:: ../CONTRIBUTING.rst
3 |
4 | Performing a Release
5 | --------------------
6 |
7 | #. Check for and fix ``pylint`` violations::
8 |
9 | paver lint -m
10 |
11 | #. Verify ``debian/changelog`` for completeness and the correct version, and bump the release date::
12 |
13 | dch -r
14 |
15 | #. Check Travis CI status at https://travis-ci.org/pyroscope/pyrocore
16 |
17 | #. Remove ‘dev’ version tagging from ``setup.cfg``, and perform a release check::
18 |
19 | sed -i -re 's/^(tag_[a-z ]+=)/##\1/' setup.cfg
20 | paver release
21 |
22 | #. Commit and tag the release::
23 |
24 | git status # check all is committed
25 | tag="v$(dpkg-parsechangelog | grep '^Version:' | awk '{print $2}')"
26 | git tag -a "$tag" -m "Release $tag"
27 |
28 | #. Build the final release and upload it to PyPI::
29 |
30 | paver dist_clean sdist bdist_wheel
31 | twine upload dist/*.{zip,whl}
32 |
--------------------------------------------------------------------------------
/docs/custom-jobs.rst:
--------------------------------------------------------------------------------
1 | .. Included in custom.rst
2 |
3 | First off, you really need to know a good amount of Python to be able to do this.
4 | But if you do, you can easily add your own background processing,
5 | more versatile and more efficient than calling ``rtcontrol`` in a cron job.
6 | The description here is terse, and mostly just tells you where to look for code examples,
7 | and the basics of how a job implementation interacts with the core system.
8 |
9 | .. note::
10 |
11 | While some effort will be spent on keeping the API backwards compatible,
12 | there is no guarantee of a stable API.
13 | Follow the commit log and changelogs of releases
14 | to get notified when you need to adapt your code.
15 |
16 | Jobs are created during ``pyrotorque`` startup and registered with the scheduler.
17 | Configuration is taken from the ``[TORQUE]`` section of ``torque.ini``,
18 | and any ``job.«job-name».«param-name»`` setting contributes to a job named ``job-name``.
19 | The ``handler``, ``schedule``, and ``active`` settings are used by the core,
20 | the rest is passed to the ``handler`` class for customization and depends on the job type.
21 |
22 | To locate the job implementation, ``handler`` contains a ``module.path:ClassName`` coordinate of its class.
23 | So ``job.foo.handler = my.code:FooJob`` registers ``FooJob`` under the name ``foo``.
24 | This means a job can be scheduled several times,
25 | given the right configuration and if the job implementation is designed for it.
26 | The given module must be importable of course,
27 | i.e. ``pip install`` it into your ``pyrocore`` virtualenv.
28 |
29 | The ``schedule`` defines the call frequency of the job's ``run`` method,
30 | and ``active`` allows to easily disable a job without removing its configuration
31 | – which is used to provide all the default jobs and their settings.
32 | A job with ``active = False`` is simply ignored and not added to the scheduler on startup.
33 |
34 | The most simple of jobs is the :any:`EngineStats` one.
35 | Click on the link and then on ``[source]`` to see its source code.
36 | Some noteworthy facts:
37 |
38 | * the initializer gets passed a ``config`` parameter, holding all the settings from ``torque.ini``
39 | for a particular job instance, with the ``job.«name»`` prefix removed.
40 | * ``pyrocore.config`` is imported as ``config_ini``, to not clash with the ``config`` dict passed into jobs.
41 | * create a ``LOG`` attribute as shown, for your logging needs.
42 | * to interact with *rTorrent*, open a proxy connection in ``run``.
43 | * the :any:`InfluxDB` job shows how to access config parameters, e.g. ``self.config.dbname``.
44 | * raise :any:`UserError` in the initializer to report configuration mishaps and prevent ``pyrotorque`` from starting.
45 |
46 | More complex jobs that you can look at are the
47 | :class:`pyrocore.torrent.watch.TreeWatch` and
48 | :class:`pyrocore.torrent.queue.QueueManager` ones.
49 |
--------------------------------------------------------------------------------
/docs/custom.rst:
--------------------------------------------------------------------------------
1 | Custom Python Code
2 | ==================
3 |
4 | You can write your own code for ``pyrocore`` implementing custom features,
5 | by adding fields, your own command line scripts, or ``pyrotorque`` jobs.
6 | You probably need a `solid grasp of Python`_ for this.
7 |
8 | .. _`solid grasp of Python`: https://github.com/TechBookHunter/Free-Python-Books#free-python-books
9 |
10 |
11 | .. _CustomFields:
12 |
13 | Defining Custom Fields
14 | ----------------------
15 |
16 | .. include:: custom-fields.rst
17 |
18 |
19 | .. _custom-template-helpers:
20 |
21 | Adding Custom Template Helpers
22 | ------------------------------
23 |
24 | In templating contexts, there is an empty ``c`` namespace (think ``custom`` or ``config``),
25 | just like ``h`` for helpers.
26 | You can populate that namespace with your own helpers as you need them,
27 | from simple string transformations to calling external programs or web interfaces.
28 |
29 | The following example illustrates the concept, and belongs into ``~/.pyroscope/config.py``.
30 |
31 | .. code-block:: python
32 |
33 | def _hostname(ip):
34 | """Helper to e.g. look up peer IPs."""
35 | import socket
36 |
37 | return socket.gethostbyaddr(ip)[0] if ip else ip
38 |
39 | custom_template_helpers.hostname = _hostname
40 |
41 | This demonstrates the call of that helper using a custom field,
42 | a real use-case would be to resolve peer IPs and the like.
43 |
44 | .. code-block:: shell
45 |
46 | $ rtcontrol -qo '{{d.fetch("custom_ip")}} → {{d.fetch("custom_ip") | c.hostname}}' // -/1
47 | 8.8.8.8 → google-public-dns-a.google.com
48 |
49 |
50 | .. _scripts:
51 |
52 |
53 | Writing Your Own Scripts
54 | ------------------------
55 |
56 | .. include:: custom-scripts.rst
57 |
58 |
59 | .. _torque-custom-jobs:
60 |
61 | Writing Custom Jobs
62 | -------------------
63 |
64 | .. include:: custom-jobs.rst
65 |
--------------------------------------------------------------------------------
/docs/examples/conky-rtorstat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/docs/examples/conky-rtorstat.png
--------------------------------------------------------------------------------
/docs/examples/ratio_histo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/docs/examples/ratio_histo.png
--------------------------------------------------------------------------------
/docs/examples/rt-backseat:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | # Throttle rTorrent for a certain amount of time
3 |
4 | #
5 | # CONFIGURATION
6 | #
7 | timeout="now + 10 minutes" # default timeout
8 | throttled=42 # throttled speed
9 | unit=1024 # unit on command line, default KiB/s
10 | queue=r
11 |
12 | #
13 | # HERE BE DRAGONS!
14 | #
15 | set -e
16 | set +x
17 |
18 | case "$1" in
19 | -h | --help)
20 | echo >&2 "Usage: $0 [«speed» [«timespec»]]"
21 | exit 1
22 | ;;
23 | *) : ;;
24 | esac
25 |
26 | if test -n "$(echo $1 | tr -d 0-9)"; then
27 | echo >&2 "ERROR: Non-numeric speed"
28 | exit 1
29 | fi
30 |
31 | if test -n "$1"; then
32 | throttled="$1"
33 | shift
34 | fi
35 | throttled=$(( $throttled * $unit ))
36 |
37 | if test -n "$1"; then
38 | timeout="$@"
39 | fi
40 |
41 | if test -n "$(atq -q $queue)"; then
42 | # If there are jobs pending, run 1st one now, and then delete them
43 | at -c $(atq -q $queue | cut -f1 | head -n1) | /bin/sh
44 | atrm $(atq -q $queue | cut -f1)
45 | fi
46 |
47 | current=$(rtxmlrpc throttle.global_down.max_rate)
48 |
49 | # Schedule new job to reset rate, and then throttle it
50 | result=$(at -q $queue $timeout <&1
51 | rtxmlrpc -q throttle.global_down.max_rate.set '' $current
52 | EOF
53 | ) || :
54 | if [[ $result =~ .*(error|arbled).* ]]; then
55 | echo >&2 "ERROR: $result"
56 | exit 1
57 | fi
58 | echo $result | sed -re "s~warning: commands will be executed using /bin/sh~~"
59 | rtxmlrpc -q throttle.global_down.max_rate.set '' $throttled
60 |
61 | echo "Speed throttled to $(( $throttled / 1024 )) KiB/s," \
62 | "back to $(( $current / 1024 )) KiB/s at $timeout."
63 |
--------------------------------------------------------------------------------
/docs/examples/rt-down-stats.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python-pyrocore
2 | # -*- coding: utf-8 -*-
3 | from __future__ import division, print_function
4 |
5 | from collections import namedtuple
6 |
7 | from pyrobase import fmt
8 | from pyrocore import config
9 | from pyrocore.util import os
10 | from pyrocore.scripts import base
11 |
12 |
13 | def fmt_duration(secs):
14 | """Format a duration in seconds."""
15 | return ' '.join(fmt.human_duration(secs, 0, precision=2, short=True).strip().split())
16 |
17 |
18 | def disk_free(path):
19 | """Return free bytes on partition holding `path`."""
20 | stats = os.statvfs(path)
21 | return stats.f_bavail * stats.f_frsize
22 |
23 |
24 | class DownloadStats(base.ScriptBaseWithConfig):
25 | """
26 | Show stats about currently active & pending downloads.
27 | """
28 |
29 | # argument description for the usage information
30 | ARGS_HELP = ""
31 |
32 | # set your own version
33 | VERSION = '1.0'
34 |
35 | FIELDS = ('is_active', 'left_bytes', 'size_bytes', 'down.rate', 'priority')
36 | MIN_STALLED_RATE = 5 * 1024
37 | STALLED_PERCENT = 10
38 |
39 | def add_options(self):
40 | """ Add program options.
41 | """
42 | super(DownloadStats, self).add_options()
43 |
44 | def mainloop(self):
45 | proxy = config.engine.open()
46 | all_items = list(config.engine.multicall("incomplete", self.FIELDS))
47 |
48 | pending = [d for d in all_items if not d.is_active and d.priority > 0]
49 | print("Queued items: ",
50 | fmt.human_size(sum(d.size_bytes for d in pending)),
51 | 'in', len(pending), 'item(s)',
52 | '[{} free]'.format(fmt.human_size(disk_free(proxy.directory.default())).strip()))
53 |
54 | items = [d for d in all_items if d.is_active]
55 | if not items:
56 | print("No active downloads!")
57 | return
58 |
59 | good_rates = [d.down_rate for d in items if d.down_rate > self.MIN_STALLED_RATE]
60 | stalled_rate = max(
61 | self.MIN_STALLED_RATE,
62 | self.STALLED_PERCENT / 100 * sum(good_rates) / len(good_rates) if good_rates else 0)
63 | stalled_count = sum(d.down_rate < stalled_rate for d in items)
64 | global_down_rate = proxy.throttle.global_down.rate()
65 |
66 | total_size = sum(d.size_bytes for d in items)
67 | total_left = sum(d.left_bytes for d in items)
68 | eta_list = [0]
69 | if stalled_count < len(items):
70 | eta_list = [d.left_bytes / d.down_rate for d in items if d.down_rate >= stalled_rate]
71 | eta_max = total_left / (global_down_rate or 1)
72 |
73 | stalled_info = ', {} stalled below {}/s'.format(
74 | stalled_count, fmt.human_size(stalled_rate).strip()) if stalled_count else ''
75 | print("Size left to download: ",
76 | fmt.human_size(total_left), 'of', fmt.human_size(total_size).strip())
77 | print("Overall download speed:", fmt.human_size(global_down_rate) + '/s')
78 | print("ETA (min → max): ",
79 | fmt_duration(min(eta_list)), '→', fmt_duration(eta_max), '…', fmt_duration(max(eta_list)),
80 | '[{} item(s){}]'.format(len(items), stalled_info),
81 | )
82 |
83 |
84 | if __name__ == '__main__':
85 | base.ScriptBase.setup()
86 | DownloadStats().run()
87 |
--------------------------------------------------------------------------------
/docs/examples/rt-heatmap.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python-pyrocore
2 | # -*- coding: utf-8 -*-
3 | import sys
4 | import subprocess
5 |
6 | import pandas as pd
7 |
8 | from pyrobase.osutil import shell_escape as quoted
9 |
10 | from pyrocore import config
11 | from pyrocore.scripts import base
12 |
13 |
14 | class HeatMap(base.ScriptBase):
15 | """
16 | Create a heatmap based on JSON data generated via `rtcontrol`.
17 |
18 | THIS IS EXPERIMENTAL, THERE'S NO SUPPORT WHATSOEVER!
19 |
20 | To run this script, you need to first install `seaborn`:
21 |
22 | ~/.local/pyroscope/bin/pip install seaborn
23 |
24 | Then, try this:
25 |
26 | rtcontrol --json -qo name,alias,ratio -A dupes= loaded=-1w \
27 | | docs/examples/rt-heapmap.py -o name alias ratio
28 |
29 | rtcontrol --json -qo tv_series,alias,ratio -A dupes= ratio=+4 loaded=-6m tv_series=\! \
30 | | docs/examples/rt-heapmap.py -o tv_series alias ratio
31 | """
32 |
33 | # argument description for the usage information
34 | ARGS_HELP = " "
35 |
36 | # set your own version
37 | VERSION = '1.0'
38 |
39 | # (optionally) define your licensing
40 | COPYRIGHT = u'Copyright (c) 2018 PyroScope Project'
41 |
42 | # Minimum upper range for color map
43 | CMAP_MIN_MAX = 4.0
44 |
45 |
46 | def add_options(self):
47 | """ Add program options.
48 | """
49 | super(HeatMap, self).add_options()
50 |
51 | # basic options
52 | self.add_bool_option('-o', '--open',
53 | help="open the resulting image file in your viewer")
54 |
55 | def heatmap(self, df, imagefile):
56 | """ Create the heat map.
57 | """
58 | import seaborn as sns
59 | import matplotlib.ticker as tkr
60 | import matplotlib.pyplot as plt
61 | from matplotlib.colors import LinearSegmentedColormap
62 |
63 | sns.set()
64 | with sns.axes_style('whitegrid'):
65 | fig, ax = plt.subplots(figsize=(5, 11)) # inches
66 |
67 | cmax = max(df[self.args[2]].max(), self.CMAP_MIN_MAX)
68 | csteps = {
69 | 0.0: 'darkred', 0.3/cmax: 'red', 0.6/cmax: 'orangered', 0.9/cmax: 'coral',
70 | 1.0/cmax: 'skyblue', 1.5/cmax: 'blue', 1.9/cmax: 'darkblue',
71 | 2.0/cmax: 'darkgreen', 3.0/cmax: 'green',
72 | (self.CMAP_MIN_MAX - .1)/cmax: 'palegreen', 1.0: 'yellow'}
73 | cmap = LinearSegmentedColormap.from_list('RdGrYl', sorted(csteps.items()), N=256)
74 |
75 | dataset = df.pivot(*self.args)
76 |
77 | sns.heatmap(dataset, mask=dataset.isnull(), annot=False, linewidths=.5, square=True, ax=ax, cmap=cmap,
78 | annot_kws=dict(stretch='condensed'))
79 | ax.tick_params(axis='y', labelrotation=30, labelsize=8)
80 | # ax.get_yaxis().set_major_formatter(tkr.FuncFormatter(lambda x, p: x))
81 | plt.savefig(imagefile)
82 |
83 | def mainloop(self):
84 | """ The main loop.
85 | """
86 | #proxy = config.engine.open()
87 |
88 | if len(self.args) != 3:
89 | self.fatal("You MUST provide names for index (row), column, and value!")
90 |
91 | # Load data
92 | df = pd.read_json(sys.stdin, orient='records')
93 | df[self.args[0]] = df[self.args[0]].str.slice(0, 42)
94 | #print(df[self.args[0]])
95 | #print(df.head(5))
96 | df = df.groupby(self.args[:2], as_index=False).mean()
97 |
98 | # Create image
99 | imagefile = 'heatmap.png'
100 | self.heatmap(df, imagefile)
101 |
102 | # Optionally show created image
103 | if self.options.open:
104 | subprocess.call("xdg-open {} &".format(quoted(imagefile)), shell=True)
105 |
106 | #self.LOG.info("XMLRPC stats: %s" % proxy)
107 |
108 |
109 | if __name__ == "__main__":
110 | base.ScriptBase.setup()
111 | HeatMap().run()
112 |
--------------------------------------------------------------------------------
/docs/examples/rt-stuck-trackers.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python-pyrocore
2 | # -*- coding: utf-8 -*-
3 |
4 | from pyrocore import config
5 | from pyrocore.scripts import base
6 |
7 |
8 | class StuckTrackers(base.ScriptBaseWithConfig):
9 | """
10 | List started items whose announces are stuck, i.e. where
11 | last activity is older than the normal announce interval.
12 | """
13 |
14 | # argument description for the usage information
15 | ARGS_HELP = ""
16 |
17 |
18 | def add_options(self):
19 | """ Add program options.
20 | """
21 | super(StuckTrackers, self).add_options()
22 |
23 | # basic options
24 | self.add_bool_option("-a", "--all",
25 | help="list ALL items, not just stuck ones")
26 | self.add_bool_option("-s", "--stuck-only",
27 | help="list just stuck items / skip 'no enabled trackers' check")
28 | self.add_bool_option("-t", "--to-tagged",
29 | help="add stuck items to 'tagged' view")
30 |
31 |
32 | def mainloop(self):
33 | import time
34 | from urlparse import urlparse
35 | from collections import namedtuple, Counter
36 |
37 | from pyrobase import fmt
38 | from pyrocore.util import xmlrpc
39 |
40 | proxy = config.engine.open()
41 | now = int(time.time())
42 | fields = ('is_enabled is_busy url min_interval normal_interval'
43 | ' activity_time_last success_counter failed_counter scrape_counter').split()
44 | t_multicall = namedtuple('multicall', fields)
45 | rows = proxy.d.multicall('started', 'd.hash=', 't.multicall=,{}'.format(
46 | ','.join(['t.{}='.format(i) for i in fields])))
47 | stuck = Counter()
48 |
49 | view = 'tagged'
50 | if self.options.to_tagged and view not in proxy.view.list():
51 | proxy.view.add(xmlrpc.NOHASH, view)
52 |
53 | print('{:>5s} {:>2s} {:>5s} {:>5s} {:>6s} {:>13s} {:40s} {}'
54 | .format('S#', 'T#', 'OK', 'Error', 'Scrape', 'Last Announce',
55 | 'Infohash', 'Tracker Domain'))
56 | for idx, (infohash, trackers) in enumerate(rows, 1):
57 | trackers = [t_multicall(*t) for t in trackers]
58 |
59 | if not any(t.is_enabled for t in trackers):
60 | if self.options.stuck_only:
61 | continue
62 | if self.options.to_tagged:
63 | proxy.d.views.push_back_unique(infohash, view)
64 | proxy.view.set_visible(infohash, view)
65 | domain = 'ALL TRACKERS DISABLED' if trackers else 'NO TRACKERS'
66 | stuck[domain] += 1
67 | print('{i:5d} {n:>2s} {n:>5s} {n:>5s} {n:>5s} {delta:>13s} {hash} {domain}'
68 | .format(i=idx, n='-', hash=infohash, delta='N/A', domain=domain))
69 | continue
70 |
71 | for num, t in enumerate(trackers, 1):
72 | if not t.is_enabled:
73 | continue
74 |
75 | delta = now - t.activity_time_last
76 | if self.options.all or delta > t.normal_interval:
77 | if self.options.to_tagged:
78 | proxy.d.views.push_back_unique(infohash, view)
79 | proxy.view.set_visible(infohash, view)
80 | domain = urlparse(t.url).netloc.split(':')[0]
81 | stuck[domain] += 1
82 |
83 | print('{i:5d} {n:2d} '
84 | '{t.success_counter:5d} {t.scrape_counter:5d} {t.failed_counter:5d} '
85 | '{delta} {hash} {domain}'
86 | .format(t=t, i=idx, n=num, hash=infohash, domain=domain,
87 | delta=fmt.human_duration(t.activity_time_last,
88 | precision=2, short=True)))
89 |
90 | if sum(stuck.values()):
91 | if self.options.to_tagged:
92 | proxy.ui.current_view.set(view)
93 | self.LOG.info("Stuck items: TOTAL={}, {}".format(sum(stuck.values()),
94 | ', '.join(['{}={}'.format(*i) for i in stuck.most_common()])))
95 | self.LOG.debug("XMLRPC stats: %s" % proxy)
96 |
97 |
98 | if __name__ == "__main__":
99 | base.ScriptBase.setup()
100 | StuckTrackers().run()
101 |
--------------------------------------------------------------------------------
/docs/examples/rt_cron_throttle_seed:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python-pyrocore
2 | import logging
3 |
4 | from pyrocore import config
5 | from pyrocore.util import fmt, matching
6 | from pyrocore.torrent import engine
7 | from pyrocore.scripts import base
8 |
9 |
10 | class SeedThrottle(base.ScriptBaseWithConfig):
11 | """
12 | Throttle seeding throttle group when other items are active.
13 | All bandwidth values are in KiB/s.
14 | """
15 |
16 | # argument description for the usage information
17 | ARGS_HELP = " "
18 |
19 | # log level for user-visible standard logging
20 | STD_LOG_LEVEL = logging.DEBUG
21 |
22 | # what items are prioritized?
23 | PRIO_FILTER = "up=+3"
24 |
25 |
26 | def add_options(self):
27 | """ Add program options.
28 | """
29 | super(SeedThrottle, self).add_options()
30 |
31 | # basic options
32 | ##self.add_bool_option("-n", "--dry-run",
33 | ## help="don't do anything, just tell what would happen")
34 |
35 |
36 | def mainloop(self):
37 | """ The main loop.
38 | """
39 | # Get proxy and parse rtorrent.rc
40 | proxy = config.engine.open()
41 |
42 | # Get arguments
43 | try:
44 | throttle_name, full_rate, nice_rate = self.args
45 | except ValueError:
46 | self.parser.error("Exactly three arguments expected")
47 |
48 | if throttle_name not in config.throttle_names:
49 | self.parser.error("Unknown throttle %r (expected one of %s)" % (
50 | throttle_name, ", ".join(config.throttle_names),
51 | ))
52 |
53 | try:
54 | full_rate = int(full_rate, 10) * 1024
55 | except (TypeError, ValueError), exc:
56 | self.parser.error("Bad full rate %r (%s)" % (full_rate, exc))
57 |
58 | try:
59 | nice_rate = int(nice_rate, 10) * 1024
60 | except (TypeError, ValueError), exc:
61 | self.parser.error("Bad nice rate %r (%s)" % (nice_rate, exc))
62 |
63 | # Check for manually changed seed rate
64 | current_rate = proxy.throttle.up.max(throttle_name)
65 | self.LOG.debug("Current '%s' rate is %s/s" % (
66 | throttle_name, fmt.human_size(current_rate).strip()
67 | ))
68 | if current_rate not in (full_rate, nice_rate):
69 | self.LOG.debug("Rate was apparently set manually, won't change it!")
70 | return
71 |
72 | # Check for active items
73 | view = config.engine.view("active", matching.ConditionParser(engine.FieldDefinition.lookup, "name").parse(
74 | "throttle=!%s [ %s ]" % (throttle_name, self.PRIO_FILTER)
75 | ))
76 | prioritized = list(view.items())
77 | self.LOG.debug("%d active items not in throttle '%s'" % (len(prioritized), throttle_name))
78 |
79 | # Set chosen bandwidth, if different
80 | rate = nice_rate if prioritized else full_rate
81 | if current_rate != rate:
82 | proxy.throttle.up(throttle_name, str(rate // 1024))
83 | self.LOG.info("THROTTLE '%s' up=%s/s [%d prioritized]" % (
84 | throttle_name,
85 | fmt.human_size(proxy.throttle.up.max(throttle_name)).strip(),
86 | len(prioritized),
87 | ))
88 |
89 | self.LOG.debug("XMLRPC stats: %s" % proxy)
90 |
91 |
92 | if __name__ == "__main__":
93 | base.ScriptBase.setup()
94 | SeedThrottle().run()
95 |
--------------------------------------------------------------------------------
/docs/examples/rtcontrol-colors.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/docs/examples/rtcontrol-colors.png
--------------------------------------------------------------------------------
/docs/examples/rtorrent-ex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/docs/examples/rtorrent-ex.png
--------------------------------------------------------------------------------
/docs/examples/rtorrent.rc:
--------------------------------------------------------------------------------
1 | ### rtorrent settings #######################################################
2 | # vim: ft=dosini
3 | # This is the standard configuration that supports both PyroScope and
4 | # (optionally) rTorrent-PS features. This file is configured for a
5 | # rTorrent instance located in
6 | #
7 | # RT_HOME
8 | #
9 | # For more info regarding changing configuration defaults, see the docs:
10 | #
11 | # https://pyrocore.readthedocs.io/en/latest/usage.html#std-config
12 | #
13 | # If you run rTorrent-PS, see below on how to unlock additional support
14 | # (but note that with version 1.1 and up, that unlocking is automatic).
15 | #
16 | #############################################################################
17 |
18 | # Root directory of this instance.
19 | method.insert = cfg.basedir, private|const|string, (cat, "RT_HOME", "/")
20 |
21 | # `system.has` polyfill (the "false=" silences the `catch` command, in rTorrent-PS 1.1+)
22 | catch = {"false=", "method.redirect=system.has,false"}
23 |
24 | # Set "pyro.extended" to 1 to activate rTorrent-PS features!
25 | method.insert = pyro.extended, const|value, (system.has, rtorrent-ps)
26 |
27 | # Set "pyro.bin_dir" to the "bin" directory where you installed the pyrocore tools!
28 | # Make sure you end it with a "/"; if this is left empty, then the shell's path is searched.
29 | method.insert = pyro.bin_dir, const|string, ~/bin/
30 |
31 | # Set this to '0' to prevent logging of existing key bindings being replaced
32 | ## branch=(pyro.extended), ((ui.bind_key.verbose.set, 0))
33 |
34 | # Since "network.scgi.open_local" is parsed by "rtcontrol", this must be a literal value,
35 | # and also not moved out of the main configuration file!
36 | network.scgi.open_local = RT_HOME/.scgi_local
37 |
38 | # SCHEDULE: Make SCGI socket group-writable and secure
39 | schedule2 = scgi_permission, 0, 0, "execute.nothrow=chmod,\"g+w,o=\",RT_HOME/.scgi_local"
40 |
41 |
42 | #
43 | # Import settings from "RT_HOME/rtorrent.d"
44 | #
45 | # Prefer to put your own custom settings into additional files in
46 | # that directory, or else "_rtlocal.rc" (see below)!
47 | #
48 |
49 | execute.throw = (cat,(pyro.bin_dir),pyroadmin),-q,--create-import,(cat,(cfg.basedir),"rtorrent.d/*.rc")
50 | import = (cat,(cfg.basedir),"rtorrent.d/.import.rc")
51 |
52 |
53 | #
54 | # Include custom / optional settings
55 | #
56 |
57 | # INCLUDE: Local settings (optional)
58 | try_import = (cat,(cfg.basedir),"_rtlocal.rc")
59 |
60 | # INCLUDE: ruTorrent (optional)
61 | try_import = (cat,(cfg.basedir),"_rutorrent.rc")
62 |
63 | ### END rtorrent.rc #########################################################
64 |
--------------------------------------------------------------------------------
/docs/examples/rtorstat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/docs/examples/rtorstat.png
--------------------------------------------------------------------------------
/docs/examples/rtuptime:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 | #
3 | # Shows some essential information about a rTorrent instance
4 | #
5 | SCGI_SOCKET=~/rtorrent/.scgi_local
6 |
7 | if test ! -S $SCGI_SOCKET; then
8 | echo >&2 "rTorrent is not running (no socket $SCGI_SOCKET)"
9 | exit 1
10 | fi
11 |
12 | echo -n rTorrent $(rtxmlrpc system.client_version)/$(rtxmlrpc system.library_version)
13 | echo -n , up $(rtxmlrpc convert.elapsed_time '' $(ls -l --time-style '+%s' $SCGI_SOCKET | awk '{print $6}'))
14 | echo -n \ [$(rtcontrol -qo"1 %(uploaded)s %(size)s" \* | \
15 | awk '{ TOT += $1; UP += $2; SUM += $3} END { print TOT " loaded; U: " UP/1024/1024/1024 " GiB; S: " SUM/1024/1024/1024 }') GiB]
16 | echo -n , D: $(rtxmlrpc convert.xb '' $(rtxmlrpc throttle.global_down.total))
17 | echo -n \ @ $(rtxmlrpc convert.xb '' $(rtxmlrpc throttle.global_down.rate))/s
18 | echo -n \ of $(rtxmlrpc convert.xb '' $(rtxmlrpc throttle.global_down.max_rate))/s
19 | echo -n , U: $(rtxmlrpc convert.xb '' $(rtxmlrpc throttle.global_up.total))
20 | echo -n \ @ $(rtxmlrpc convert.xb '' $(rtxmlrpc throttle.global_up.rate))/s
21 | echo -n \ of $(rtxmlrpc convert.xb '' $(rtxmlrpc throttle.global_up.max_rate))/s
22 | echo
23 |
--------------------------------------------------------------------------------
/docs/examples/start.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # rTorrent startup script
4 | #
5 |
6 | NOCRON_DELAY=600
7 | RT_BINDIR="{{ rtorrent_bindir }}"
8 | RT_OPTS=( )
9 | RT_OPTS+=( -D -I ) # comment this to get deprecated commands
10 |
11 | builtin cd "$(dirname "$0")"
12 | export RT_HOME="$(pwd -P)"
13 |
14 | fail() {
15 | echo "ERROR:" "$@"
16 | exit 1
17 | }
18 |
19 | # Performa a mount check
20 | #test -f "$RT_HOME/work/.mounted" -a -f "$RT_HOME/done/.mounted" \
21 | # || fail "Data drive(s) not mounted!"
22 |
23 |
24 | if [ "$TERM" = "${TERM%-256color}" ]; then
25 | export TERM="$TERM-256color"
26 | fi
27 |
28 | export LANG=en_US.UTF-8
29 | umask 0027
30 |
31 | RT_OPTS+=( -n -o "import=$RT_HOME/rtorrent.rc" )
32 |
33 | export RT_SOCKET=$PWD/.scgi_local
34 | test -S $RT_SOCKET && lsof $RT_SOCKET >/dev/null && { echo "rTorrent already running"; exit 1; }
35 | test ! -e $RT_SOCKET || rm $RT_SOCKET
36 |
37 | _at_exit() {
38 | test -z "$TMUX" || tmux set-w automatic-rename on >/dev/null
39 | stty sane
40 | test ! -e $RT_SOCKET || rm $RT_SOCKET
41 | }
42 | trap _at_exit INT TERM EXIT
43 | test -z "$TMUX" || tmux 'rename-w' 'rT-PS'
44 |
45 | if test -n "$RT_BINDIR"; then
46 | RT_BINDIR="${RT_BINDIR%/}/"
47 |
48 | # Try usual suspects if config is wrong
49 | test -x "${RT_BINDIR}rtorrent" || RT_BINDIR="$HOME/bin/"
50 | test -x "${RT_BINDIR}rtorrent" || RT_BINDIR="/opt/rtorrent/bin/"
51 | test -x "${RT_BINDIR}rtorrent" || RT_BINDIR="/usr/local/bin/"
52 | test -x "${RT_BINDIR}rtorrent" || RT_BINDIR="/usr/bin/"
53 | test -x "${RT_BINDIR}rtorrent" || RT_BINDIR=""
54 | fi
55 | #RT_BINDIR="$HOME/src/rtorrent-ps/rtorrent-0.9.6/src/"
56 | export RT_BIN="${RT_BINDIR}rtorrent"
57 |
58 | if which objdump >/dev/null; then
59 | RUNPATH=$(objdump -x "$RT_BIN" | grep RPATH | sed -re 's/ *RPATH *//')
60 | test -n "$RUNPATH" || RUNPATH=$(objdump -x "$RT_BIN" | grep RUNPATH | sed -re 's/ *RUNPATH *//')
61 | test -z "$RUNPATH" || LD_LIBRARY_PATH="$RUNPATH${LD_LIBRARY_PATH:+:}${LD_LIBRARY_PATH}"
62 | fi
63 |
64 | # Stop cron jobs during startup, unless already stopped
65 | rm "$RT_HOME/rtorrent.d/START-NOCRON.rc" 2>/dev/null || :
66 | nocron_delay=''
67 | if test -d "$RT_HOME/rtorrent.d" -a ! -f "~/NOCRON"; then
68 | nocron_delay=$(( $(date +'%s') + $NOCRON_DELAY ))
69 | echo >"$RT_HOME/rtorrent.d/START-NOCRON.rc" \
70 | "schedule2 = nocron_during_startup, $NOCRON_DELAY, 0, \"execute.nothrow=rm,$HOME/NOCRON\""
71 | touch "$HOME/NOCRON"
72 | fi
73 |
74 | "$RT_BIN" "${RT_OPTS[@]}" ; RC=$?
75 | test -z "$nocron_delay" -o "$(date +'%s')" -ge "${nocron_delay:-0}" || rm "$HOME/NOCRON" 2>/dev/null || :
76 | exit $RC
77 |
--------------------------------------------------------------------------------
/docs/examples/tmux.conf:
--------------------------------------------------------------------------------
1 | # PyroScope default tmux configuration
2 |
3 | # Rebind to Ctrl-a
4 | set -g prefix C-a
5 | unbind C-b
6 | bind a send-prefix
7 | bind C-a last-window
8 | bind '"' choose-window
9 |
10 | # Rebind pane splitting
11 | unbind %
12 | bind - split-window -v
13 | bind _ split-window -h
14 |
15 | # Set status bar
16 | set -g status-bg colour236
17 | set -g status-fg white
18 | set -g status-left '#[fg=green]#H'
19 |
20 | # Highlight active window
21 | set-window-option -g window-status-current-bg colour164
22 |
23 | # Force 256 colors
24 | set -g default-terminal "screen-256color"
25 |
--------------------------------------------------------------------------------
/docs/include-api-uml.rst:
--------------------------------------------------------------------------------
1 | UML Diagrams
2 | ------------
3 |
4 |
5 | All Classes
6 | ^^^^^^^^^^^
7 |
8 | .. uml:: pyrocore -k
9 |
10 | Exceptions
11 | ^^^^^^^^^^
12 |
13 | .. uml:: -a2 -b
14 | ../src/pyrocore/error.py
15 |
16 | rTorrent API
17 | ^^^^^^^^^^^^
18 |
19 | .. uml:: -s1
20 | ../src/pyrocore/torrent/rtorrent.py
21 |
22 | .. uml:: -s2
23 | ../src/pyrocore/torrent/engine.py
24 |
25 |
26 | Filter Rules
27 | ^^^^^^^^^^^^
28 |
29 | .. uml:: -s1
30 | ../src/pyrocore/util/matching.py
31 |
32 | Scripts
33 | ^^^^^^^
34 |
35 | .. uml:: pyrocore.scripts
36 |
37 | Configuration
38 | ^^^^^^^^^^^^^
39 |
40 | .. uml:: ../src/pyrocore/util/load_config.py
41 |
42 | Metafile
43 | ^^^^^^^^
44 |
45 | .. uml:: ../src/pyrocore/util/metafile.py
46 |
47 | Tree Watch
48 | ^^^^^^^^^^
49 |
50 | .. uml:: pyrocore.torrent.watch
51 |
--------------------------------------------------------------------------------
/docs/include-contacts.rst:
--------------------------------------------------------------------------------
1 | .. included at several places
2 |
3 | .. image:: https://raw.githubusercontent.com/pyroscope/pyrocore/master/docs/_static/img/help.png
4 | :align: left
5 |
6 | To get in contact and share your experiences with other users of `PyroScope`_,
7 | join the `rtorrent-community`_ channel `pyroscope-tools`_ on Gitter.
8 |
9 | This is also the way to resolve any problems with or questions about your configuration
10 | and software installation.
11 | *Always* look into the :doc:`troubleshooting` as a first measure,
12 | which is often the fastest way to get back to a working system.
13 | That guide also explains how to efficiently report your problem when you cannot fix it yourself.
14 |
15 | .. _`PyroScope`: https://github.com/pyroscope
16 | .. _`rtorrent-community`: https://gitter.im/rtorrent-community/
17 | .. _`pyroscope-tools`: https://gitter.im/rtorrent-community/pyroscope-tools
18 | .. _`pyroscope-users`: http://groups.google.com/group/pyroscope-users
19 |
--------------------------------------------------------------------------------
/docs/include-xmlrpc-dialects.rst:
--------------------------------------------------------------------------------
1 | .. included at several places
2 |
3 | .. warning::
4 |
5 | The syntax of XMLRPC commands changed with rTorrent version 0.8.9,
6 | and continues to change. Make sure that the versions of rTorrent
7 | and PyroScope you plan to install or update to are actually compatible.
8 | There are compensation mechanisms in both projects, but there are limits to those
9 | — scan the respective changelogs for breaking changes.
10 |
11 | *pyrocore* 0.5+ will no longer support the old syntax, and thus not work
12 | with *rTorrent* 0.8.x versions.
13 | *rTorrent* 0.9.6 has the old commands disabled by default, and only a
14 | special command line switch will enable them again, *for now*.
15 | Also, this documentation uses the new syntax (mostly).
16 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. pyrocore documentation master file, created by
2 | sphinx-quickstart on Sat May 2 16:17:52 2015.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | .. image:: _static/img/logo.png
7 |
8 | Welcome to pyrocore's documentation!
9 | ====================================
10 |
11 | *pyrocore* is a collection of tools for the BitTorrent protocol
12 | and especially the rTorrent client.
13 | They enable you to filter rTorrent's item list for displaying or changing selected items,
14 | also creating, inspecting and changing ``.torrent`` files, and much more.
15 |
16 | An optional daemon process named :command:`pyrotorque` can add flexible queue management for rTorrent,
17 | starting items added in bulk slowly over time according to customizable rules.
18 |
19 | It can also watch a directory tree recursively for new metafiles using *inotify*.
20 | That means ``.torrent`` files you drop anywhere into that watched tree are loaded instantaneously,
21 | without any polling and no extra configuration for nested directories.
22 |
23 | .. note::
24 |
25 | The *PyroScope* command line utilities (i.e. *pyrocore*) are *not* the same as `rTorrent-PS`_,
26 | and they work perfectly fine without it; the same is true the other
27 | way 'round.
28 | It's just that both projects unsurprisingly have synergies if used together,
29 | and some features *do* only work when both are present.
30 |
31 | You absolutely **must** read the first three chapters
32 | :doc:`overview`, :doc:`installation`, and :doc:`setup`,
33 | and follow their instructions.
34 | Otherwise *pyrocore* utilities won't work at all or not properly,
35 | if you do not provide an adequate :file:`config.ini` file, and also modify
36 | the *rTorrent* one to provide some essential data and commands.
37 |
38 | Once you got everything basically working, :doc:`usage`
39 | will show you all the common commands and use-cases. Further chapters then explain
40 | more complex use-cases and features that might not appeal or apply to you.
41 |
42 | .. include:: include-contacts.rst
43 |
44 |
45 | Contents of This Manual
46 | =======================
47 |
48 | .. toctree::
49 | :maxdepth: 2
50 | :caption: Getting Started
51 |
52 | overview
53 | installation
54 | setup
55 | usage
56 |
57 | .. toctree::
58 | :maxdepth: 2
59 | :caption: Advanced Usage
60 |
61 | howto
62 | advanced
63 | custom
64 |
65 | .. toctree::
66 | :maxdepth: 2
67 | :caption: Other Topics
68 |
69 | troubleshooting
70 | updating
71 | tempita
72 | references
73 | license
74 |
75 | .. toctree::
76 | :maxdepth: 2
77 | :caption: Development
78 |
79 | experimental
80 | api
81 | contributing
82 |
83 |
84 | Indices & Tables
85 | ----------------
86 |
87 | * :ref:`genindex`
88 | * :ref:`modindex`
89 | * :ref:`search`
90 |
--------------------------------------------------------------------------------
/docs/license.rst:
--------------------------------------------------------------------------------
1 | License
2 | =======
3 |
4 | .. include:: ../LICENSE
5 |
--------------------------------------------------------------------------------
/docs/overview.rst:
--------------------------------------------------------------------------------
1 | Overview
2 | ========
3 |
4 | Introduction
5 | ------------
6 |
7 | *pyrocore* is part of the `PyroScope`_ family of projects, and offers a
8 | collection of tools for the :ref:`bt-protocol` and especially the
9 | *rTorrent* client. This includes:
10 |
11 | * :ref:`command-line-tools` for automation of common tasks, like :ref:`metafile creation `, and
12 | :ref:`filtering and mass-changing your loaded torrents `.
13 | * rTorrent extensions like a :ref:`QueueManager` and statistics (*work in progress*).
14 | * All this is based on the ``pyrocore`` Python package, that you can
15 | use for :ref:`scripts` for any special needs that aren't covered by
16 | the standard tools.
17 |
18 | See the
19 | `ScreenShotGallery `_
20 | if you want to get a first impression without installing the software.
21 |
22 | .. include:: include-contacts.rst
23 |
24 | .. _`PyroScope`: https://github.com/pyroscope
25 |
26 |
27 | .. _glossary:
28 |
29 | Glossary
30 | --------
31 |
32 | To help you better understand this manual,
33 | here are the definitions of some key concepts used in it.
34 |
35 | (download) item
36 | An item loaded into rTorrent.
37 |
38 | field
39 | An attribute of a download item, e.g. ``name``, ``completed``, and ``directory``.
40 | Most of these you know from *rTorrent* or *ruTorrent*, but *PyroScope* adds some of its own.
41 | They are used in conditions to filter items using the ``rtcontrol`` tool,
42 | and also name the things you want to print to the console when listing items.
43 | To get a full list, use the ``rtcontrol --help-fields`` command.
44 |
45 | metafile
46 | The term *metafile* means the ``.torrent`` file – using 'torrent' is avoided intentionally,
47 | because it's often used ambiguously to mean *either* the metafile or the *data* of a download item.
48 |
49 | XMLRPC
50 | The protocol used to remotely control a running rTorrent process.
51 | Note that support for XMLRPC is an option that must be activated when compiling
52 | the rTorrent binary, so make sure it's active in your installation
53 | when 'nothing works' for you. A quick way to check is calling the following command:
54 |
55 | .. code-block:: bash
56 |
57 | $ ldd $(command which rtorrent) | grep libxmlrpc.so
58 | libxmlrpc.so.3 => /home/pyroscope/.local/rtorrent/0.9.6-PS-1.0/lib/libxmlrpc.so.3 …
59 |
60 |
61 | Quick Start Guide
62 | -----------------
63 |
64 | Work through these chapters in order to get the software up and running,
65 | and to learn basic concepts of using the command line tools.
66 |
67 | * :doc:`installation`
68 | * :doc:`setup`
69 | * :doc:`usage`
70 |
71 | Consult the :doc:`troubleshooting` if anything goes wrong.
72 | :ref:`issue-reporting` explains how to provide feedback in case
73 | you encounter a serious problem, or are missing a feature.
74 |
75 | .. warning::
76 |
77 | If you do a fresh installation of *pyrocore* in addition to an existing
78 | *rTorrent* one, you will need to follow the instructions
79 | to :ref:`backfill-data`, which fills in some data your already
80 | running rTorrent instance is missing otherwise! So do **not**
81 | skip that section.
82 |
83 |
84 | Further Information & Customization
85 | -----------------------------------
86 |
87 | * :doc:`howto` highlights some specific use-cases and might
88 | give you some inspiration when solving your own problems.
89 | * Using :doc:`advanced` requires some knowledge in the area Linux,
90 | Bash, and Python beyond a novice level, but they enable you to
91 | customize your setup even further and handle very specific use-cases.
92 | * :doc:`custom` tells you about :ref:`scripts` as an easy way to automate anything
93 | that the standard commands can't do.
94 | There are more ways for adding your own custom logic,
95 | amongst them :ref:`CustomFields` for adding user-defined fields,
96 | available in ``rtcontrol`` just like built-in ones.
97 | * :doc:`updating` explains how to get newer versions
98 | of this software after the initial installation.
99 | * :doc:`references` provides details on technical background topics
100 | like XMLRPC, and links into the web with related information.
101 |
--------------------------------------------------------------------------------
/docs/references.rst:
--------------------------------------------------------------------------------
1 | References
2 | ==========
3 |
4 | .. _cli-usage:
5 |
6 | PyroScope CLI Tools Usage
7 | -------------------------
8 |
9 | This section is automatically generated and shows the options available
10 | in the *development* version of the code (git HEAD).
11 | See :doc:`usage` for more details on how to use these commands.
12 |
13 | .. include:: references-cli-usage.rst
14 |
15 |
16 | .. _RtXmlRpcReference:
17 |
18 | rTorrent XMLRPC
19 | ---------------
20 |
21 | See the `Commands Reference`_ in the *rTorrent Handbook* for a list of available commands and what they do.
22 | The `Scripting Guide`_ explains how all these fit together.
23 |
24 | .. _`Commands Reference`: https://rtorrent-docs.readthedocs.io/en/latest/cmd-ref.html
25 | .. _`Scripting Guide`: https://rtorrent-docs.readthedocs.io/en/latest/scripting.html
26 |
27 | XMLRPC Migration
28 | ----------------
29 |
30 | The syntax of XMLRPC commands changed with rTorrent version 0.8.9,
31 | and continues to change. The old command names and behavior were
32 | replaced with aliases and marked for deprecation, so they still work for now,
33 | but don't rely on that and use the new names instead.
34 |
35 | See `XMLRPC Migration`_ in the GitHub wiki for details.
36 |
37 | .. _`XMLRPC Migration`: https://github.com/rakshasa/rtorrent/wiki/RPC-Migration-0.9
38 |
39 |
40 | Books & Other Knowledge Sources
41 | -------------------------------
42 |
43 | This and related documentation cannot teach all you need to know in order
44 | to run a torrent client and manage the server it is installed on.
45 |
46 | So here are a few references to either books or web resources that help you
47 | to improve your basic know-how, in case you have trouble following some parts of the docs.
48 |
49 | **Linux / CLI / Administration**
50 |
51 | * `The Debian Administrator's Handbook`_
52 | * `The Linux Command Line`_
53 | * `The Art of Command Line`_
54 | * `Ansible Documentation`_
55 |
56 | **Python**
57 |
58 | * `The Hitchhiker’s Guide to Python`_
59 | * `Free Python Books`_
60 |
61 | .. _The Debian Administrator's Handbook: https://debian-handbook.info/browse/stable/
62 | .. _The Linux Command Line: http://linuxcommand.org/tlcl.php
63 | .. _The Art of Command Line: https://github.com/jlevy/the-art-of-command-line#the-art-of-command-line
64 | .. _Ansible Documentation: https://docs.ansible.com/#ansible-documentation
65 |
66 | .. _`The Hitchhiker’s Guide to Python`: http://docs.python-guide.org/
67 | .. _`Free Python Books`: https://github.com/TechBookHunter/Free-Python-Books#free-python-books
68 |
69 |
70 | External Links
71 | --------------
72 |
73 | * `User Mailing List `_
74 | * The `rTorrent `_
75 | and `libtorrent `_ projects
76 | * `rTorrent Community Wiki `_
77 | and the `rTorrent Handbook `_
78 | * `Open HUB `_
79 | * `free(code) `_
80 | * `Bintray `_
81 | * `pyrobase `_
82 |
83 |
84 | .. _bt-protocol:
85 |
86 | BitTorrent Protocol
87 | -------------------
88 |
89 | Wikipedia:
90 |
91 | * `Protocol `_
92 | * `bencode `_
93 |
94 | BitTorrent standards:
95 |
96 | * `Index of BitTorrent Enhancement Proposals `_
97 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | # requirements for use on "Read The Docs"
2 | pylint==1.7.0
3 | ##sphinx-pyreverse==0.0.12
4 | ##https://github.com/pyroscope/sphinx-pyreverse/archive/master.zip#egg=sphinx-pyreverse
5 |
6 | -r ../requirements-torque.txt
7 |
--------------------------------------------------------------------------------
/docs/usage.rst:
--------------------------------------------------------------------------------
1 | User's Manual
2 | =============
3 |
4 | This chapter provides an overview of all the command line tools and their everyday use,
5 | focussing on :command:`rtcontrol` as the most powerful of them.
6 | The following chapters then go into more advanced use-cases and features.
7 |
8 |
9 | .. _CommandLineTools:
10 | .. _command-line-tools:
11 |
12 | Command Line Tools
13 | ------------------
14 |
15 | .. include:: usage-cli-tools.rst
16 |
17 |
18 | .. _rtcontrol-examples:
19 |
20 | ‘rtcontrol’ Examples
21 | --------------------
22 |
23 | .. include:: usage-rtcontrol.rst
24 |
25 |
26 | .. _output-templates:
27 |
28 | Using Output Templates
29 | ----------------------
30 |
31 | .. include:: usage-templates.rst
32 |
33 |
34 | .. _std-config:
35 |
36 | Standard Configuration Explained
37 | --------------------------------
38 |
39 | .. include:: usage-std-config.rst
40 |
--------------------------------------------------------------------------------
/docs/videos/bash-completion.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/docs/videos/bash-completion.gif
--------------------------------------------------------------------------------
/docs/videos/rtcontrol-curses.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/docs/videos/rtcontrol-curses.gif
--------------------------------------------------------------------------------
/paver-minilib.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pyroscope/pyrocore/e8ededb6d9f3702ede6cd5396e6b473915637b64/paver-minilib.zip
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | # Full list of tools for development
2 | Paver==1.2.4
3 | bpython==0.17.1
4 | twine==1.11.0
5 | pip-upgrader
6 |
7 | Sphinx==1.7.5
8 | sphinx-rtd-theme==0.4.0
9 | sphinx-autobuild==0.7.1
10 |
11 | nose==1.3.7
12 |
13 | -r docs/requirements.txt
14 |
--------------------------------------------------------------------------------
/requirements-torque.txt:
--------------------------------------------------------------------------------
1 | # pip requirements for "pyrotorque" dependencies
2 |
3 | APScheduler==2.1.0
4 | pyinotify>=0.9.6
5 | waitress>=0.9.0
6 | WebOb>=1.6.1
7 | psutil>=4.3.0
8 |
9 | -r requirements.txt
10 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # requirements for installation
2 | Tempita>=0.5.1
3 | ProxyTypes==0.9
4 | pyrobase>=0.5
5 | #-e git+https://github.com/pyroscope/pyrobase.git#egg=pyrobase
6 | auvyon>=0.1
7 | requests>=2.10,<3
8 | prompt-toolkit>=1.0.14,<2
9 | six==1.9.0
10 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [egg_info]
2 | tag_build = dev
3 | tag_date = true
4 |
5 | [sdist]
6 | formats = zip
7 |
8 | [upload]
9 | show_response = 1
10 |
11 | [nosetests]
12 | #where = src
13 | verbosity = 0
14 | detailed-errors = 1
15 | with-coverage = 1
16 | cover-html = 1
17 | cover-html-dir = ../build/coverage
18 | cover-package = pyrocore
19 |
20 | # logging during tests
21 | #quiet = 1
22 | #nocapture = 1
23 | #nologcapture = 1
24 | logging-config = src/tests/logging.cfg
25 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | try:
2 | import paver.tasks
3 | except ImportError:
4 | from os.path import exists
5 | if exists("paver-minilib.zip"):
6 | import sys
7 | sys.path.insert(0, "paver-minilib.zip")
8 | import paver.tasks
9 |
10 | paver.tasks.main()
11 |
--------------------------------------------------------------------------------
/src/pyrocore/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # pylint: disable=
3 | """ Python Torrent Tools Core Package.
4 |
5 | Copyright (c) 2010 The PyroScope Project
6 | """
7 | # This program is free software; you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation; either version 2 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License along
18 | # with this program; if not, write to the Free Software Foundation, Inc.,
19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 | from __future__ import absolute_import
21 |
22 |
23 | def connect(config_dir=None, optional_config_files=None, cron_cfg="cron"):
24 | """ Initialize everything for interactive use.
25 |
26 | Returns a ready-to-use RtorrentEngine object.
27 | """
28 | from pyrocore.scripts.base import ScriptBase
29 | from pyrocore.util import load_config
30 |
31 | ScriptBase.setup(cron_cfg=cron_cfg)
32 | load_config.ConfigLoader(config_dir).load(optional_config_files or [])
33 |
34 | from pyrocore import config
35 | config.engine.open()
36 | return config.engine
37 |
38 |
39 | def view(viewname='default', matcher=None,
40 | config_dir=None, optional_config_files=None, cron_cfg="cron"):
41 | """Helper for interactive / high-level API use."""
42 | return connect(config_dir, optional_config_files, cron_cfg).view(viewname, matcher)
43 |
--------------------------------------------------------------------------------
/src/pyrocore/config.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # pylint: disable=I0011,C0103,W0404
3 | """ Configuration.
4 |
5 | For details, see https://pyrocore.readthedocs.io/en/latest/setup.html
6 |
7 | Copyright (c) 2009, 2010, 2011 The PyroScope Project
8 | """
9 | # This program is free software; you can redistribute it and/or modify
10 | # it under the terms of the GNU General Public License as published by
11 | # the Free Software Foundation; either version 2 of the License, or
12 | # (at your option) any later version.
13 | #
14 | # This program is distributed in the hope that it will be useful,
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | # GNU General Public License for more details.
18 | #
19 | # You should have received a copy of the GNU General Public License along
20 | # with this program; if not, write to the Free Software Foundation, Inc.,
21 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 | from __future__ import absolute_import
23 |
24 | from pyrobase.parts import Bunch
25 |
26 |
27 | def lookup_announce_alias(name):
28 | """ Get canonical alias name and announce URL list for the given alias.
29 | """
30 | for alias, urls in announce.items():
31 | if alias.lower() == name.lower():
32 | return alias, urls
33 |
34 | raise KeyError("Unknown alias %s" % (name,))
35 |
36 |
37 | def map_announce2alias(url):
38 | """ Get tracker alias for announce URL, and if none is defined, the 2nd level domain.
39 | """
40 | import urlparse
41 |
42 | # Try to find an exact alias URL match and return its label
43 | for alias, urls in announce.items():
44 | if any(i == url for i in urls):
45 | return alias
46 |
47 | # Try to find an alias URL prefix and return its label
48 | parts = urlparse.urlparse(url)
49 | server = urlparse.urlunparse((parts.scheme, parts.netloc, "/", None, None, None))
50 |
51 | for alias, urls in announce.items():
52 | if any(i.startswith(server) for i in urls):
53 | return alias
54 |
55 | # Return 2nd level domain name if no alias found
56 | try:
57 | return '.'.join(parts.netloc.split(':')[0].split('.')[-2:])
58 | except IndexError:
59 | return parts.netloc
60 |
61 | # Remember predefined names
62 | _PREDEFINED = tuple(_ for _ in globals() if not _.startswith('_'))
63 |
64 | # Set some defaults to shut up pydev / pylint;
65 | # these later get overwritten by loading the config
66 | debug = False
67 | config_dir = None
68 | scgi_url = ""
69 | engine = Bunch(open=lambda: None)
70 | fast_query = 0
71 | formats = {}
72 | sort_fields = ""
73 | announce = {}
74 | config_validator_callbacks = []
75 | custom_field_factories = []
76 | custom_template_helpers = Bunch()
77 | xmlrpc = {}
78 | output_header_ecma48 = ""
79 | output_header_frequency = 1
80 | waif_pattern_list = []
81 | traits_by_alias = {}
82 | torque = {}
83 | magnet_watch = None
84 | influxdb = {}
85 |
--------------------------------------------------------------------------------
/src/pyrocore/daemon/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # pylint: disable=
3 | """ Background Daemon Package.
4 |
5 | Copyright (c) 2012 The PyroScope Project
6 | """
7 | # This program is free software; you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation; either version 2 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License along
18 | # with this program; if not, write to the Free Software Foundation, Inc.,
19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/bash-completion:
--------------------------------------------------------------------------------
1 | # bash completion for PyroScope commands
2 | #
3 | # Source this in your ~/.bash_completion or ~/.bashrc,
4 | # or copy it to /etc/bash_completion.d/pyrocore
5 | #
6 | _pyrocore_base() {
7 | COMPREPLY=()
8 | cur="${COMP_WORDS[COMP_CWORD]}"
9 | prev="${COMP_WORDS[COMP_CWORD-1]}"
10 |
11 | case "${prev}" in
12 | --config-dir)
13 | COMPREPLY=( $(compgen -A directory -- "${cur}") )
14 | return 0
15 | ;;
16 | esac
17 | }
18 |
19 | _pyrocore_generic() {
20 | local cur prev choices
21 | _pyrocore_base
22 | test -z "$COMPREPLY" || return 0
23 |
24 | case "${cur}" in
25 | -*)
26 | choices="$(${COMP_WORDS[0]} --help-completion-options)"
27 | COMPREPLY=( $(compgen -W "${choices}" -- ${cur}) )
28 | return 0
29 | ;;
30 | esac
31 | }
32 |
33 | _rtxmlrpc() {
34 | local cur prev choices
35 | _pyrocore_base
36 | test -z "$COMPREPLY" || return 0
37 |
38 | case "${cur}" in
39 | -*)
40 | choices="$(rtxmlrpc --help-completion-options)"
41 | COMPREPLY=( $(compgen -W "${choices}" -- ${cur}) )
42 | return 0
43 | ;;
44 | [a-z]*)
45 | choices="$(rtxmlrpc system.listMethods)"
46 | COMPREPLY=( $(compgen -W "${choices}" -- ${cur}) )
47 | return 0
48 | ;;
49 | esac
50 | }
51 |
52 | _rtcontrol() {
53 | local cur prev choices
54 | _pyrocore_base
55 | test -z "$COMPREPLY" || return 0
56 |
57 | case "${prev}" in
58 | #--custom=KEY=VALUE"
59 | #--define=KEY=VAL [-D ...]"
60 |
61 | --from-view | --to-view)
62 | choices="$(rtxmlrpc view_list)"
63 | COMPREPLY=( $(compgen -W "${choices}" -- "${cur##*=}") )
64 | return 0
65 | ;;
66 |
67 | --ignore)
68 | COMPREPLY=( $(compgen -W "0 1" -- "${cur}") )
69 | return 0
70 | ;;
71 |
72 | -O | --output-template)
73 | COMPREPLY=( $(compgen -A file -- "${cur}") )
74 | return 0
75 | ;;
76 |
77 | -o | --output-format | -s | --sort-fields)
78 | choices="$(rtcontrol --help-completion-fields | cut -f1 -d=)"
79 | if test "${cur}" == "${cur##*,}"; then
80 | COMPREPLY=( $(compgen -S, -W "${choices}" -- "${cur}") )
81 | else
82 | COMPREPLY=( $(compgen -P "${cur%,*}," -S, -W "${choices}" -- "${cur##*,}") )
83 | fi
84 | return 0
85 | ;;
86 |
87 | #--tag="TAG +TAG -TAG...""
88 | #-T | --throttle=NAME"
89 | esac
90 |
91 | case "${cur}" in
92 | -*)
93 | choices="$(rtcontrol --help-completion-options)"
94 | COMPREPLY=( $(compgen -W "${choices}" -- ${cur}) )
95 | return 0
96 | ;;
97 | or | O)
98 | COMPREPLY=( OR )
99 | return 0
100 | ;;
101 | alias=*)
102 | choices="$(rtcontrol -qo alias -s* \* | tr A-Z a-z | uniq)"
103 | if test "${cur}" == "${cur##*,}"; then
104 | COMPREPLY=( $(compgen -S, -W "${choices}" -- "${cur##*=}") )
105 | else
106 | prev="${cur##*=}"
107 | prev="${prev%,*}"
108 | COMPREPLY=( $(compgen -P "${prev}," -S, -W "${choices}" -- "${cur##*,}") )
109 | fi
110 | return 0
111 | ;;
112 | [a-z]*=*)
113 | choices="$(rtcontrol --help-completion-fields | egrep ^${cur}. | cut -f2 -d=)"
114 | COMPREPLY=( $(compgen -W "${choices}" -- "${cur##*=*}") )
115 | return 0
116 | ;;
117 | [a-z]*)
118 | choices="$(rtcontrol --help-completion-fields)"
119 | COMPREPLY=( $(compgen -W "${choices}" -- "${cur}") )
120 | return 0
121 | ;;
122 | esac
123 | }
124 |
125 | complete -F _rtxmlrpc rtxmlrpc
126 | complete -F _rtcontrol rtcontrol
127 | complete -F _pyrocore_generic pyroadmin
128 | complete -F _pyrocore_generic -f chtor lstor
129 | complete -F _pyrocore_generic -o default hashcheck mktor rtevent rtmv
130 |
131 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/color-schemes/default-16.rc:
--------------------------------------------------------------------------------
1 | # Color scheme for 16 ANSI colors
2 |
3 | pyro.color_theme.name = "Default (16 ANSI colors)"
4 |
5 | ui.color.alarm.set = "bold white on red"
6 | ui.color.complete.set = "bright green"
7 | #ui.color.custom1.set = "gray"
8 | ui.color.even.set = ""
9 | ui.color.focus.set = "reverse"
10 | ui.color.footer.set = "bold bright cyan on blue"
11 | ui.color.incomplete.set = "yellow"
12 | ui.color.info.set = "white"
13 | ui.color.label.set = "bright blue"
14 | ui.color.leeching.set = "bold bright yellow"
15 | ui.color.odd.set = ""
16 | ui.color.progress0.set = "red"
17 | ui.color.progress20.set = "bold bright red"
18 | ui.color.progress40.set = "bold bright magenta"
19 | ui.color.progress60.set = "yellow"
20 | ui.color.progress80.set = "bold bright yellow"
21 | ui.color.progress100.set = "green"
22 | ui.color.progress120.set = "bold bright green"
23 | ui.color.queued.set = "magenta"
24 | ui.color.seeding.set = "bold bright green"
25 | ui.color.stopped.set = "blue"
26 | ui.color.title.set = "bold bright white on blue"
27 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/color-schemes/default-256.rc:
--------------------------------------------------------------------------------
1 | # Color scheme for 256 xterm colors
2 |
3 | pyro.color_theme.name = "Default (256 xterm colors)"
4 |
5 | ui.color.alarm.set = "bold white on red"
6 | ui.color.complete.set = "41"
7 | #ui.color.custom1.set = 242
8 | ui.color.even.set = "on 234"
9 | ui.color.focus.set = "reverse"
10 | ui.color.footer.set = "bright cyan on 20"
11 | ui.color.incomplete.set = "yellow"
12 | ui.color.info.set = "white"
13 | ui.color.label.set = 105
14 | ui.color.leeching.set = "bold bright yellow"
15 | ui.color.odd.set = "on 232"
16 | ui.color.progress0.set = "196"
17 | ui.color.progress100.set = "34"
18 | ui.color.progress120.set = "bold bright 47"
19 | ui.color.progress20.set = "202"
20 | ui.color.progress40.set = "213"
21 | ui.color.progress60.set = "214"
22 | ui.color.progress80.set = "226"
23 | ui.color.queued.set = "magenta"
24 | ui.color.seeding.set = "bold bright 46"
25 | ui.color.stopped.set = "33"
26 | ui.color.title.set = "bold bright white on blue"
27 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/color-schemes/default-8.rc:
--------------------------------------------------------------------------------
1 | # Color scheme for 8 ANSI colors
2 |
3 | pyro.color_theme.name = "Default (8 ANSI colors)"
4 |
5 | ui.color.alarm.set = "white on red"
6 | ui.color.complete.set = "white"
7 | #ui.color.custom1.set = "gray"
8 | ui.color.even.set = ""
9 | ui.color.focus.set = "reverse"
10 | ui.color.footer.set = "white on blue"
11 | ui.color.incomplete.set = "yellow"
12 | ui.color.info.set = "white"
13 | ui.color.label.set = "gray"
14 | ui.color.leeching.set = "yellow"
15 | ui.color.odd.set = ""
16 | ui.color.progress0.set = "red"
17 | ui.color.progress20.set = "red"
18 | ui.color.progress40.set = "magenta"
19 | ui.color.progress60.set = "yellow"
20 | ui.color.progress80.set = "yellow"
21 | ui.color.progress100.set = "green"
22 | ui.color.progress120.set = "green"
23 | ui.color.queued.set = "magenta"
24 | ui.color.seeding.set = "green"
25 | ui.color.stopped.set = "blue"
26 | ui.color.title.set = "white on blue"
27 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/color-schemes/happy-pastel.rc:
--------------------------------------------------------------------------------
1 | # Color scheme for 256 xterm colors - Happy Pastel (less harsh default colors with a happy touch)
2 |
3 | pyro.color_theme.name = "Happy Pastel"
4 |
5 | ui.color.alarm.set = "bold 250 on 124"
6 | ui.color.complete.set = "41"
7 | #ui.color.custom1.set = 242
8 | ui.color.even.set = "on 234"
9 | ui.color.focus.set = "reverse"
10 | ui.color.footer.set = "bright 123 on 160"
11 | ui.color.incomplete.set = "221"
12 | ui.color.info.set = "white"
13 | ui.color.label.set = "241"
14 | ui.color.leeching.set = "bold bright 220"
15 | ui.color.odd.set = "on 232"
16 | ui.color.progress0.set = "196"
17 | ui.color.progress20.set = "207"
18 | ui.color.progress40.set = "202"
19 | ui.color.progress60.set = "214"
20 | ui.color.progress80.set = "226"
21 | ui.color.progress100.set = "34"
22 | ui.color.progress120.set = "bold bright 46"
23 | ui.color.queued.set = "133"
24 | ui.color.seeding.set = "bold bright 40"
25 | ui.color.stopped.set = "33"
26 | ui.color.title.set = "bold bright white on 202"
27 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/color-schemes/solarized-blue.rc:
--------------------------------------------------------------------------------
1 | # Color scheme for 256 xterm colors - Solarized Blue (http://ethanschoonover.com/solarized)
2 |
3 | pyro.color_theme.name = "Solarized Blue"
4 |
5 | ui.color.alarm.set = "bold 254 on 160"
6 | ui.color.complete.set = "33"
7 | #ui.color.custom1.set = 242
8 | ui.color.even.set = "on 234"
9 | ui.color.focus.set = "reverse"
10 | ui.color.footer.set = "bright 254 on 125"
11 | ui.color.incomplete.set = "136"
12 | ui.color.info.set = "245"
13 | ui.color.label.set = "240"
14 | ui.color.leeching.set = "bold bright 166"
15 | ui.color.odd.set = ""
16 | ui.color.progress0.set = "160"
17 | ui.color.progress20.set = "61"
18 | ui.color.progress40.set = "64"
19 | ui.color.progress60.set = "166"
20 | ui.color.progress80.set = "136"
21 | ui.color.progress100.set = "33"
22 | ui.color.progress120.set = "bold bright 37"
23 | ui.color.queued.set = "125"
24 | ui.color.seeding.set = "bold bright 37"
25 | ui.color.stopped.set = "64"
26 | ui.color.title.set = "bold bright 230 on 61"
27 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/color-schemes/solarized-yellow.rc:
--------------------------------------------------------------------------------
1 | # Color scheme for 256 xterm colors - Solarized Yellow (http://ethanschoonover.com/solarized)
2 |
3 | pyro.color_theme.name = "Solarized Yellow"
4 |
5 | ui.color.alarm.set = "bold 254 on 160"
6 | ui.color.complete.set = "136"
7 | #ui.color.custom1.set = 242
8 | ui.color.even.set = "on 234"
9 | ui.color.focus.set = "reverse"
10 | ui.color.footer.set = "bright 254 on 160"
11 | ui.color.incomplete.set = "64"
12 | ui.color.info.set = "245"
13 | ui.color.label.set = "240"
14 | ui.color.leeching.set = "bold bright 70"
15 | ui.color.odd.set = ""
16 | ui.color.progress0.set = "160"
17 | ui.color.progress20.set = "61"
18 | ui.color.progress40.set = "33"
19 | ui.color.progress60.set = "37"
20 | ui.color.progress80.set = "64"
21 | ui.color.progress100.set = "136"
22 | ui.color.progress120.set = "bold bright 166"
23 | ui.color.queued.set = "125"
24 | ui.color.seeding.set = "bold bright 166"
25 | ui.color.stopped.set = "33"
26 | ui.color.title.set = "bold bright 230 on 64"
27 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/config.py:
--------------------------------------------------------------------------------
1 | # The default PyroScope configuration script
2 | #
3 | # For details, see https://pyrocore.readthedocs.io/en/latest/setup.html
4 | # and https://pyrocore.readthedocs.io/en/latest/custom.html#defining-custom-fields
5 | #
6 |
7 | def _custom_fields():
8 | """ Yield custom field definitions.
9 | """
10 | # Import some commonly needed modules
11 | import os
12 | from pyrocore.torrent import engine, matching
13 | from pyrocore.util import fmt
14 |
15 | # PUT CUSTOM FIELD CODE HERE
16 |
17 | # Disk space check (as an example)
18 | # see https://pyrocore.readthedocs.io/en/latest/custom.html#has-room
19 | def has_room(obj):
20 | "Check disk space."
21 | pathname = obj.path
22 | if pathname and not os.path.exists(pathname):
23 | pathname = os.path.dirname(pathname)
24 | if pathname and os.path.exists(pathname):
25 | stats = os.statvfs(pathname)
26 | return (stats.f_bavail * stats.f_frsize - int(diskspace_threshold_mb) * 1024**2
27 | > obj.size * (1.0 - obj.done / 100.0))
28 | else:
29 | return None
30 |
31 | yield engine.DynamicField(engine.untyped, "has_room",
32 | "check whether the download will fit on its target device",
33 | matcher=matching.BoolFilter, accessor=has_room,
34 | formatter=lambda val: "OK" if val else "??" if val is None else "NO")
35 | globals().setdefault("diskspace_threshold_mb", "500")
36 |
37 |
38 | # Register our factory with the system
39 | custom_field_factories.append(_custom_fields)
40 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/logging.cron.ini:
--------------------------------------------------------------------------------
1 | # Logging configuration for command line scripts in cron mode
2 | #
3 | # For details see http://docs.python.org/library/logging.html#configuring-logging
4 | #
5 |
6 | [loggers]
7 | keys = root
8 |
9 | [handlers]
10 | keys = cronlog
11 |
12 | [formatters]
13 | keys = cronlog
14 |
15 | [logger_root]
16 | level = INFO
17 | handlers = cronlog
18 |
19 | [handler_cronlog]
20 | class = FileHandler
21 | args = (HERE + '/log/cron.log', 'a')
22 | level = INFO
23 | formatter = cronlog
24 |
25 | [formatter_cronlog]
26 | format = %(asctime)s %(levelname)-8s %(message)s [%(name)s]
27 | datefmt = %Y-%m-%d %H:%M:%S
28 |
29 | # %(name)s Name of the logger (logging channel).
30 | # %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).
31 | # %(levelname)s Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
32 | # %(pathname)s Full pathname of the source file where the logging call was issued (if available).
33 | # %(filename)s Filename portion of pathname.
34 | # %(module)s Module (name portion of filename).
35 | # %(funcName)s Name of function containing the logging call.
36 | # %(lineno)d Source line number where the logging call was issued (if available).
37 | # %(created)f Time when the LogRecord was created (as returned by time.time()).
38 | # %(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
39 | # %(asctime)s Human-readable time when the LogRecord was created. By default this is of the form “2003-07-08 16:49:45,896” (the numbers after the comma are millisecond portion of the time).
40 | # %(msecs)d Millisecond portion of the time when the LogRecord was created.
41 | # %(thread)d Thread ID (if available).
42 | # %(threadName)s Thread name (if available).
43 | # %(process)d Process ID (if available).
44 | # %(message)s The logged message, computed as msg % args.
45 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/logging.scripts.ini:
--------------------------------------------------------------------------------
1 | # Logging configuration for command line scripts
2 | #
3 | # For details see http://docs.python.org/library/logging.html#configuring-logging
4 | #
5 |
6 | [loggers]
7 | keys = root
8 | #keys = root, pyrocore
9 |
10 | [handlers]
11 | keys = console
12 |
13 | [formatters]
14 | keys = console
15 |
16 | [logger_root]
17 | level = INFO
18 | handlers = console
19 |
20 | [logger_pyrocore]
21 | level = DEBUG
22 | handlers = console
23 | qualname = pyrocore
24 | propagate = 0
25 |
26 | [handler_console]
27 | class = StreamHandler
28 | level = NOTSET
29 | formatter = console
30 | args = (sys.stdout,)
31 |
32 | [formatter_console]
33 | format = %(levelname)-8s %(message)s
34 | #format = %(asctime)s %(levelname)-8s %(message)s [%(name)s]
35 | #datefmt = %Y-%m-%d %H:%M:%S
36 |
37 | # %(name)s Name of the logger (logging channel).
38 | # %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).
39 | # %(levelname)s Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
40 | # %(pathname)s Full pathname of the source file where the logging call was issued (if available).
41 | # %(filename)s Filename portion of pathname.
42 | # %(module)s Module (name portion of filename).
43 | # %(funcName)s Name of function containing the logging call.
44 | # %(lineno)d Source line number where the logging call was issued (if available).
45 | # %(created)f Time when the LogRecord was created (as returned by time.time()).
46 | # %(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
47 | # %(asctime)s Human-readable time when the LogRecord was created. By default this is of the form “2003-07-08 16:49:45,896” (the numbers after the comma are millisecond portion of the time).
48 | # %(msecs)d Millisecond portion of the time when the LogRecord was created.
49 | # %(thread)d Thread ID (if available).
50 | # %(threadName)s Thread name (if available).
51 | # %(process)d Process ID (if available).
52 | # %(message)s The logged message, computed as msg % args.
53 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/logging.torque.ini:
--------------------------------------------------------------------------------
1 | # Logging configuration for `pyrotorque` in cron mode
2 | #
3 | # For details see http://docs.python.org/library/logging.html#configuring-logging
4 | #
5 |
6 | [loggers]
7 | keys = root, scheduler
8 |
9 | [logger_root]
10 | level = INFO
11 | handlers = torquelog
12 |
13 | [logger_scheduler]
14 | level = WARN
15 | qualname = apscheduler.scheduler
16 | propagate = 1
17 | handlers =
18 |
19 | [handlers]
20 | keys = torquelog
21 |
22 | [handler_torquelog]
23 | level = DEBUG
24 | formatter = torquelog
25 | class = FileHandler
26 | args = (HERE + '/log/torque.log', 'a')
27 |
28 | [formatters]
29 | keys = torquelog
30 |
31 | [formatter_torquelog]
32 | format = %(asctime)s %(levelname)-8s %(message)s [%(name)s]
33 | datefmt = %Y-%m-%d %H:%M:%S
34 |
35 | # %(name)s Name of the logger (logging channel).
36 | # %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).
37 | # %(levelname)s Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
38 | # %(pathname)s Full pathname of the source file where the logging call was issued (if available).
39 | # %(filename)s Filename portion of pathname.
40 | # %(module)s Module (name portion of filename).
41 | # %(funcName)s Name of function containing the logging call.
42 | # %(lineno)d Source line number where the logging call was issued (if available).
43 | # %(created)f Time when the LogRecord was created (as returned by time.time()).
44 | # %(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
45 | # %(asctime)s Human-readable time when the LogRecord was created. By default this is of the form “2003-07-08 16:49:45,896” (the numbers after the comma are millisecond portion of the time).
46 | # %(msecs)d Millisecond portion of the time when the LogRecord was created.
47 | # %(thread)d Thread ID (if available).
48 | # %(threadName)s Thread name (if available).
49 | # %(process)d Process ID (if available).
50 | # %(message)s The logged message, computed as msg % args.
51 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent-pyro.rc:
--------------------------------------------------------------------------------
1 | #############################################################################
2 | # Standard PyroScope rTorrent Configuration
3 | #
4 | # To include THIS file into your main "~/.rtorrent.rc", add these commands to it:
5 | # method.insert = pyro.extended, value|const, 0
6 | # method.insert = pyro.bin_dir, string|const,
7 | # import = ~/.pyroscope/rtorrent-pyro.rc.default
8 | #
9 | # And read https://pyrocore.readthedocs.io/en/latest/setup.html#rtorrent-pyro-rc
10 | #
11 | # Remove the ".default" if you want to change something (else your changes
12 | # get over-written on update, when you put them into ``*.default`` files).
13 | # The BETTER way to apply customizations is to use the ``.rcignore`` file
14 | # to disable the specific ``*.rc.default`` file, and then provide your own
15 | # version in an EXTRA file.
16 | #
17 | # Set "pyro.extended" to 1 to activate rTorrent-PS features, but ONLY if
18 | # you actually run that patched version of rTorrent!
19 | #
20 |
21 | # Import files from "~/.pyroscope/rtorrent.d" (default versions)
22 | execute.throw = (cat,(pyro.bin_dir),pyroadmin),-q,--create-import,~/.pyroscope/rtorrent.d/*.rc.default
23 | import = ~/.pyroscope/rtorrent.d/.import.rc
24 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/00-default.rc:
--------------------------------------------------------------------------------
1 | ### Fundamentals ############################################################
2 | # vim: ft=dosini
3 |
4 | # Log extension switch setting
5 | branch=pyro.extended=,\
6 | print=rTorrent-PS\\\ features\\\ active!,\
7 | print=rTorrent-PS\\\ features\\\ NOT\\\ active!
8 |
9 | # COMMAND: Return startup time (can be used to calculate uptime)
10 | method.insert = system.startup_time, value|const, $system.time=
11 | #method.redirect = startup_time, system.startup_time
12 |
13 | # COMMAND: `do` fall-back?
14 | branch = (not, (system.has, "do=")), ((catch, \
15 | ((print, "WARNING: Fall-back for 'do' command active (update rTorrent-PS)!")), \
16 | ((method.redirect, do, catch)) ))
17 |
18 | # COMMAND: Return path to item data (never empty, unlike `d.base_path`);
19 | # multi-file items return a path ending with a '/'.
20 | method.insert = d.data_path, simple,\
21 | "if=(d.is_multi_file),\
22 | (cat, (d.directory), /),\
23 | (cat, (d.directory), /, (d.name))"
24 |
25 | # COMMAND: Return path to session file
26 | method.insert = d.session_file, simple, "cat=(session.path), (d.hash), .torrent"
27 |
28 | # COMMAND: Get mtime of a path, return 2nd argument when path does not exist
29 | method.insert = os.path.mtime, simple, \
30 | "execute.capture = sh, -c, \
31 | \"echo -n \$(stat -c '%Y' \\\"$1\\\" 2>/dev/null || echo \\\"$2\\\")\", \
32 | getmtime, (argument.0), (argument.1)"
33 |
34 | # COMMAND: Fallback through completed / loaded / downloaded event timestamps, for view sorting
35 | # (MUST be protected by the caller using a system.has=d.custom.if_z= check)
36 | method.insert = pyro._view_sort_timestamp, simple|private, \
37 | "d.custom.if_z = tm_completed, (d.custom.if_z, tm_loaded, (d.custom, tm_downloaded))"
38 |
39 | # COMMAND: Start command for watches, with dynamic behaviour
40 | method.insert.value = cfg.watch.start, 1
41 | method.insert = d.watch.start, simple, "branch=cfg.watch.start=, ((d.start))"
42 | method.insert = d.watch.startable, private|simple, "d.custom.set = watch_start, 1"
43 | method.set_key = event.download.inserted_new, ~watch_start, "branch=d.custom=watch_start,d.watch.start="
44 |
45 | # COMMAND: Nicer key binds (hide technical complications)
46 | method.insert = pyro._bind_schedule, private|simple,\
47 | "schedule2=(argument.0), 1, 0, (argument.1)"
48 | method.insert = pyro._bind_key_command, private|simple,\
49 | "cat=\"ui.bind_key=download_list,\",$argument.0=,\",\\\"\",$argument.1=, \"\\\"\""
50 | method.insert = pyro.bind_key, private|simple,\
51 | "branch=(pyro.extended),\
52 | ((pyro._bind_schedule, (argument.0), (pyro._bind_key_command, (argument.1), (argument.2))))"
53 |
54 | # COMMAND: Safely toggle collapsed state of views
55 | method.insert = pyro.view.collapsed.toggle, private|simple,\
56 | "branch=(pyro.extended), ((view.collapsed.toggle, (argument.0)))"
57 | method.insert = pyro.collapsed_view.add, private|simple,\
58 | "view.add=(argument.0) ; pyro.view.collapsed.toggle=(argument.0)"
59 |
60 | # UI/VIEW: Bind "*" to toggle between collapsed and expanded display
61 | branch=(not, (system.has, canvas_v2)), \
62 | ((pyro.bind_key, collapsed_view_toggle, *, "view.collapsed.toggle="))
63 |
64 | # UI/VIEW: Default view for filtering results (bound to '^' key in rT-PS)
65 | pyro.collapsed_view.add = rtcontrol
66 | view.filter = rtcontrol, ((false))
67 | pyro.bind_key = rtcontrol_view, ^, "ui.current_view.set=rtcontrol"
68 |
69 | # UI/Key: Press 'u' for uptime
70 | method.insert = pyro._elapsed_time, private|simple,\
71 | "branch=(system.has, convert.time_delta=), \
72 | \"convert.time_delta=$value=$argument.0=\", \
73 | \"convert.elapsed_time=$value=$argument.0=\""
74 | method.insert = pyro._print_uptime, private|simple,\
75 | "print=\"rTorrent \", $system.library_version=,\
76 | /, $system.client_version=,\
77 | \" started \", $convert.date=$system.startup_time=,\
78 | \" \", $convert.time=$system.startup_time=,\
79 | \", up \", $pyro._elapsed_time=$system.startup_time=,\
80 | \" [PID=\", $system.pid=,],\
81 | \" [CWD=\", $system.cwd=,]"
82 |
83 | pyro.bind_key = print_uptime, u, "pyro._print_uptime="
84 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/auto-scrape.rc:
--------------------------------------------------------------------------------
1 | ### Tracker Auto-Scraping ###################################################
2 | # vim: ft=dosini
3 | #
4 | # To disable this, use
5 | #
6 | # echo >>~/.pyroscope/rtorrent.d/.rcignore "auto-scrape.rc.default"
7 | #
8 | # [devised by @chros73]
9 |
10 | # Regularly update scrape information for all torrents, even stopped ones.
11 | # It won't affect the operation of rtorrent, but it is nice to have these values updated.
12 | # By default, this info is only updated when rtorrent starts or a torrent is added.
13 | #
14 | # Try to balance calls to not fire them up at the same time, since multiscraping
15 | # isn't implemented in libtorrent.
16 | #
17 | # Polls for elapsed scrape intervals every 5 minutes, and splits items into two groups:
18 | # - data-transferring items: update every 10 minutes
19 | # - idle or stopped items: update every 12 hours
20 | #
21 | # To check the scrape status, just list recorded scrape times in order:
22 | #
23 | # rtcontrol --from started -s* -qco custom_tm_last_scrape.raw.delta,name //
24 | #
25 | # To debug, call this after startup (on a test instance with just a few items):
26 | #
27 | # rtxmlrpc pyro.scrape_verbose.set=,1 ; rtxmlrpc pyro.scrape_interval.idle.set=,200
28 |
29 | # VALUE: Enable verbose mode by setting to '1' → log any scrape, not just manual ones
30 | method.insert.value = pyro.scrape_verbose, 0
31 |
32 | # VALUE: Scrape intervals (for active and idle items)
33 | method.insert.value = pyro.scrape_interval.active, 600
34 | method.insert.value = pyro.scrape_interval.idle, 43200
35 |
36 |
37 | # HELPER: Log a scraping event
38 | method.insert = pyro._last_scrape.print, simple|private,\
39 | "print=\"Sending scrape for #\",$d.hash=,\" \",[,$d.name=,]"
40 |
41 | # HELPER: Set current time in a custom field (tm_last_scrape) and save session
42 | method.insert = pyro._last_scrape.bump, simple|private,\
43 | "d.custom.set=tm_last_scrape, $cat=$system.time= ; d.save_resume="
44 |
45 | # COMMAND: Send the scrape request, set 'tm_last_scrape' timestamp, and save session
46 | method.insert = d.tracker.bump_scrape, simple,\
47 | "d.tracker.send_scrape=0 ; pyro._last_scrape.bump= ; branch=pyro.scrape_verbose=,pyro._last_scrape.print="
48 |
49 | # HELPER: Check if the required time interval (arg.0) has passed,
50 | # if yes then call 'd.tracker.bump_scrape'
51 | method.insert = pyro._scrape.send_after, simple|private,\
52 | "branch={(elapsed.greater, $d.custom=tm_last_scrape, $argument.0=), d.tracker.bump_scrape=}"
53 |
54 | # HELPER: Check for non-existing or empty custom field,
55 | # to be able to test its validity later
56 | method.insert = pyro._last_scrape.poll, simple|private,\
57 | "branch={d.custom=tm_last_scrape, pyro._scrape.send_after=$argument.0=, d.tracker.bump_scrape=}"
58 |
59 | # SCHEDULE: Check for elapsed intervals every 5 minutes, and update scrape info
60 | # for active items and idle/stopped ones according to their interval settings.
61 | schedule2 = pyro_last_scrape_check, 333, 300,\
62 | ((d.multicall2,default,\
63 | "branch=\"or={d.up.rate=,d.down.rate=,}\",\
64 | pyro._last_scrape.poll=$pyro.scrape_interval.active=,\
65 | pyro._last_scrape.poll=$pyro.scrape_interval.idle="))
66 |
67 | # EVENT: Initialize 'tm_last_scrape' for newly added items
68 | method.set_key = event.download.inserted_new, pyro_last_scrape_init, "pyro._last_scrape.bump="
69 |
70 | # UI/Key: Manually send scrape with "&"
71 | pyro.bind_key = manual_scrape, &, "d.tracker.bump_scrape= ; branch=pyro.scrape_verbose=,false=,pyro._last_scrape.print="
72 |
73 | # Scrape a little after completion (on average after 30 sec)
74 | pyro.collapsed_view.add = scheduled_scrape_once
75 | view.filter = scheduled_scrape_once, ((false))
76 | method.insert = pyro._add_to_scheduled_scrape_once, simple|private,\
77 | "d.views.push_back_unique = scheduled_scrape_once ; \
78 | view.set_visible = scheduled_scrape_once"
79 | method.set_key = event.download.finished, !add_to_scheduled_scrape_once, \
80 | ((pyro._add_to_scheduled_scrape_once))
81 | schedule2 = do_scheduled_scrape_once, 127, 60, \
82 | ((d.multicall2, scheduled_scrape_once, \
83 | "d.tracker.bump_scrape=", \
84 | "d.views.remove = scheduled_scrape_once", \
85 | "view.set_not_visible = scheduled_scrape_once"))
86 |
87 | # END auto-scrape
88 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/bind-navigation-keys.rc:
--------------------------------------------------------------------------------
1 | ### UI/Keys: PgUp/Dn, Home, End #############################################
2 | # vim: ft=dosini
3 | #
4 | # To disable this, use
5 | #
6 | # echo >>~/.pyroscope/rtorrent.d/.rcignore "bind-navigation-keys.rc.default"
7 | #
8 | # See the "Trouble-Shooting Guide" in the manual for when and why to do that.
9 |
10 | pyro.bind_key = navigation_home, 0406, "ui.focus.home="
11 | pyro.bind_key = navigation_end, 0550, "ui.focus.end="
12 | pyro.bind_key = navigation_pgup, 0523, "ui.focus.pgup="
13 | pyro.bind_key = navigation_pgdn, 0522, "ui.focus.pgdn="
14 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/collapse-built-in-views.rc:
--------------------------------------------------------------------------------
1 | ### UI/VIEW: Collapse all built-in views ####################################
2 | # vim: ft=dosini
3 | #
4 | # To disable this, use
5 | #
6 | # echo >>~/.pyroscope/rtorrent.d/.rcignore "collapse-built-in-views.rc.default"
7 | #
8 |
9 | # PS 1.1+ has the built-in views collapsed by default!
10 | branch=(not, (system.has, "collapsed-views")), ((do, \
11 | "pyro.view.collapsed.toggle = active", \
12 | "pyro.view.collapsed.toggle = complete", \
13 | "pyro.view.collapsed.toggle = hashing", \
14 | "pyro.view.collapsed.toggle = incomplete", \
15 | "pyro.view.collapsed.toggle = leeching", \
16 | "pyro.view.collapsed.toggle = main", \
17 | "pyro.view.collapsed.toggle = name", \
18 | "pyro.view.collapsed.toggle = seeding", \
19 | "pyro.view.collapsed.toggle = started", \
20 | "pyro.view.collapsed.toggle = stopped" ))
21 |
22 | # EOF
23 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/commands.rc:
--------------------------------------------------------------------------------
1 | ### UI Helper Commands (Ctrl-X) #############################################
2 | # vim: ft=dosini
3 |
4 | # UI/CMD: Use rtcontrol filter (^X s=KEYWORD, ^X t=TRACKER, ^X f="FILTER")
5 | method.insert = s, simple|private,\
6 | "execute.nothrow=\"$cat=$pyro.bin_dir=,rtcontrol\",--detach,-qV,\
7 | [,\"$cat=*,$argument.0=,*\",OR,\"$cat=custom_displayname=,*,$argument.0=,*\",]"
8 | method.insert = t, simple|private,\
9 | "execute.nothrow=\"$cat=$pyro.bin_dir=,rtcontrol\",--detach,-qV,\"$cat=\\\"alias=\\\",$argument.0=\""
10 | method.insert = f, simple|private,\
11 | "execute.nothrow=\"$cat=$pyro.bin_dir=,rtcontrol\",--detach,-qV,$argument.0="
12 |
13 | # UI/CMD: Housekeeping (delete item + data)
14 | method.insert = purge, simple|private,\
15 | "execute.nothrow=\"$cat=$pyro.bin_dir=,rtcontrol\",-q,--detach,--purge,--yes,--from-view,$d.hash=,//"
16 | method.insert = cull, simple|private,\
17 | "execute.nothrow=\"$cat=$pyro.bin_dir=,rtcontrol\",-q,--detach,--cull,--yes,--from-view,$d.hash=,//"
18 |
19 | # UI/CMD: Add, remove, and show tags
20 | method.insert = tag.show, simple|private,\
21 | "execute.nothrow=\"$cat=$pyro.bin_dir=,rtcontrol\",--detach,-qV,-otag_show,--from-view,$d.hash=,//,--flush"
22 | #method.insert = tag.show, simple|private,\
23 | # "print=\"Tags: \",$d.custom=tags"
24 |
25 | method.insert = tag.add, simple|private,\
26 | "execute.nothrow=\"$cat=$pyro.bin_dir=,rtcontrol\",--detach,-qV,-otag_show,--flush,--yes,--from-view,$d.hash=,//,--tag,$argument.0="
27 |
28 | method.insert = tag.rm, simple|private,\
29 | "execute.nothrow=\"$cat=$pyro.bin_dir=,rtcontrol\",--detach,-qV,-otag_show,--flush,--yes,--from-view,$d.hash=,//,--tag,\"$cat=-,$argument.0=\""
30 |
31 | # UI/Key: Ctrl-G shows the tags of the current item
32 | pyro.bind_key = tag_show, ^G, "tag.show="
33 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/helper-methods.rc:
--------------------------------------------------------------------------------
1 | # vim: ft=dosini
2 | # refactoring made this empty for now
3 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/logging.rc:
--------------------------------------------------------------------------------
1 | ### Event Logging ###########################################################
2 | # vim: ft=dosini
3 | #
4 | # To disable this, use
5 | #
6 | # echo >>~/.pyroscope/rtorrent.d/.rcignore "logging.rc.default"
7 |
8 | catch = {false=, "method.insert.simple = string.replace, \"cat=(argument.0)\""}
9 | method.insert = pyro._date_now, simple|private, \
10 | "string.replace = (convert.date, (system.time_seconds)), {/, .}"
11 |
12 | # Logging + UI: Add day break to log
13 | schedule2 = log_new_day, 00:00:05, 24:00:00, ((print, "New day: ", ((pyro._date_now)) ))
14 |
15 | # Emit regular warning when ~/NOCRON exists
16 | schedule2 = log_nocron, 900, 1800, "branch = (value, (os.path.mtime, ~/NOCRON, 0)), \
17 | ((print, \"WARNING: Cron jobs disabled by ~/NOCRON\"))"
18 |
19 | # EVENTS: Logging (don't log "opened", or you get swamped at startup)
20 | method.insert = pyro._log_on_event, simple|private, \
21 | "print = $argument.0=, $d.name=, \" [\", $pyro._date_now=, \"]\""
22 |
23 | method.set_key = event.download.inserted_new, ~log, ((pyro._log_on_event, "LOADED "))
24 | method.set_key = event.download.finished, ~log, ((pyro._log_on_event, "COMPLETED "))
25 | method.set_key = event.download.closed, ~log, ((pyro._log_on_event, "CLOSED "))
26 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/quick-help.rc:
--------------------------------------------------------------------------------
1 | ### UI: Show quick help resources ###########################################
2 | # vim: ft=dosini
3 | #
4 | # To disable this, use
5 | #
6 | # echo >>~/.pyroscope/rtorrent.d/.rcignore "quick-help.rc.default"
7 |
8 | method.insert = pyro.print_help, multi|rlookup|static
9 | method.set_key = pyro.print_help, !!intro1, ((print, ""))
10 | method.set_key = pyro.print_help, !!intro2, ((print, ((cat,\
11 | "rTorrent QUICK HELP RESOURCES" )) ))
12 | method.set_key = pyro.print_help, !!intro3, ((print, ((cat,\
13 | "=============================" )) ))
14 | method.set_key = pyro.print_help, !10handbook, ((print, ((cat,\
15 | "rTorrent Handbook http://rtorrent-docs.readthedocs.io/" )) ))
16 | method.set_key = pyro.print_help, !10wiki, ((print, ((cat,\
17 | "rTorrent Wiki https://github.com/rakshasa/rtorrent/wiki" )) ))
18 | method.set_key = pyro.print_help, !20pyrocore, ((print, ((cat,\
19 | "pyrocore Manual (rtcontrol) https://pyrocore.readthedocs.io/" )) ))
20 |
21 | # Bind to F2
22 | pyro.bind_key = quick_help, 0412, "pyro.print_help="
23 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/theming.rc:
--------------------------------------------------------------------------------
1 | ### UI/Colors: Rotate through color schemes #################################
2 | # vim: ft=dosini
3 | #
4 | # (De-)select a theme: python-pyrocore -m pyrocore.ui.theming -t ‹name(s)›
5 | # Select all themes: python-pyrocore -m pyrocore.ui.theming -a
6 | # List all themes: python-pyrocore -m pyrocore.ui.theming -l
7 | # Rotate to next: python-pyrocore -m pyrocore.ui.theming -qn
8 | # Print current path: python-pyrocore -m pyrocore.ui.theming -qc
9 | #
10 | # Example:
11 | #
12 | # python-pyrocore -m pyrocore.ui.theming -a -t default-256,solarized-blue,solarized-yellow,happy-pastel -l
13 |
14 | # UI/Key: Bind theme rotation to '~'
15 | pyro.bind_key = rotate_theme, ~,\
16 | "try_import=(execute.capture_nothrow, (cat,(pyro.bin_dir),python-pyrocore), -m, pyrocore.ui.theming, -qn)"
17 |
18 | # HELPER: This is used within theme files, currently just announces the switch
19 | method.insert = pyro.color_theme.name, private|simple,\
20 | "print = (cat, \"Switched to '\", (argument.0), \"' color theme\")"
21 |
22 | # HELPER: Load the currently active theme (on startup)
23 | method.insert = pyro._load_current_theme, private|simple,\
24 | "try_import=(execute.capture_nothrow, (cat,(pyro.bin_dir),python-pyrocore), -m, pyrocore.ui.theming, -qc)"
25 |
26 | # Load @ startup
27 | branch=(pyro.extended), ((pyro._load_current_theme))
28 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/timestamps.rc:
--------------------------------------------------------------------------------
1 | ### EVENTS: Timestamps ######################################################
2 | # vim: ft=dosini
3 | # tm_loaded = time loaded into client
4 | # tm_started = time of *first* start
5 | # tm_completed = time of completion
6 |
7 | method.insert = pyro._tm_started.now, simple|private,\
8 | "d.custom.set=tm_started,$cat=$system.time= ; d.save_resume="
9 | method.insert = pyro._tm_completed.now, simple|private,\
10 | "d.custom.set=tm_completed,$cat=$system.time= ; d.save_resume="
11 |
12 | method.set_key = event.download.resumed, !time_stamp,\
13 | "branch=d.custom=tm_started,false=,pyro._tm_started.now="
14 | method.set_key = event.download.inserted_new, !time_stamp,\
15 | "d.custom.set=tm_loaded,$cat=$system.time= ; d.save_resume="
16 | method.set_key = event.download.finished, !time_stamp,\
17 | "pyro._tm_completed.now="
18 | method.set_key = event.download.hash_done, !time_stamp,\
19 | "branch=\"and={d.complete=,not=$d.custom=tm_completed}\", pyro._tm_completed.now="
20 |
21 |
22 | # EVENTS: Activation intervals
23 | method.insert = pyro._activations.append, simple|private,\
24 | "d.custom.set=activations,\"$cat=$d.custom=activations,$argument.0=,$system.time=\" ; d.save_resume="
25 | method.set_key = event.download.paused, !activations, "pyro._activations.append=P"
26 | method.set_key = event.download.resumed, !activations, "pyro._activations.append=R"
27 |
28 |
29 | # EVENTS: Timestamp 'tm_downloaded' (time when meta (torrent) file was downloaded)
30 | method.insert = pyro._tm_downloaded_init, simple|private,\
31 | "d.custom.set = tm_downloaded, (os.path.mtime, (d.tied_to_file), (cat, (system.time))) ; d.save_resume="
32 | method.insert = d.timestamp.downloaded, simple, "d.custom=tm_downloaded"
33 | method.set_key = event.download.inserted_new, set_downloaded_date, ((pyro._tm_downloaded_init))
34 |
35 |
36 | # SCHEDULE: Set "last_active" custom timestamp field for items that have peers
37 | method.insert = d.timestamp.last_active, simple, "if=$d.peers_connected=,$cat=$system.time=,$d.custom=last_active"
38 | method.insert = d.timestamp.last_active.update, simple|private,\
39 | "d.custom.set=last_active,$cat=$system.time= ; branch=argument.0=,d.save_resume="
40 |
41 | schedule2 = pyro_update_last_active, 24, 42,\
42 | "d.multicall2=started,\"branch=$d.peers_connected=,d.timestamp.last_active.update=\""
43 |
44 | method.set_key = event.download.resumed, !last_active,\
45 | "branch=\"or={d.peers_connected=,not=$d.custom=last_active}\", d.timestamp.last_active.update=1"
46 | method.set_key = event.download.finished, !last_active, "d.timestamp.last_active.update=1"
47 |
48 | method.insert = d.timestamp.last_active.print, simple|private,\
49 | "print=\"$cat={$convert.date=$d.timestamp.last_active=, \\\" \\\", $convert.time=$d.timestamp.last_active=}\""
50 |
51 |
52 | # SCHEDULE: Set "last_xfer" custom timestamp field for items that transfer data
53 | method.insert.value = pyro.last_xfer.min_rate, 5000
54 |
55 | method.insert = pyro._last_xfer_check_min_rate, simple|private,\
56 | "greater=argument.0=,pyro.last_xfer.min_rate="
57 | method.insert = pyro._last_xfer_update, simple|private,\
58 | "d.custom.set=last_xfer,$cat=$system.time= ; branch=argument.0=,d.save_resume="
59 | method.insert = d.last_xfer.is_active, simple,\
60 | "or={pyro._last_xfer_check_min_rate=$d.up.rate=,pyro._last_xfer_check_min_rate=$d.down.rate=}"
61 | method.insert = d.timestamp.last_xfer, simple, "if=$d.last_xfer.is_active=,$cat=$system.time=,$d.custom=last_xfer"
62 |
63 | schedule2 = pyro_update_last_xfer, 33, 17,\
64 | "d.multicall2=active,\"branch=$d.last_xfer.is_active=,pyro._last_xfer_update=\""
65 |
66 | method.insert = d.timestamp.last_xfer.print, simple|private,\
67 | "print=\"$cat={$convert.date=$d.timestamp.last_xfer=, \\\" \\\", $convert.time=$d.timestamp.last_xfer=}\""
68 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/torque.rc:
--------------------------------------------------------------------------------
1 | ### TORQUE: View for queue manager job ######################################
2 | # vim: ft=dosini
3 | #
4 | # This is not the buggy internal scheduler controlled by scheduler.max_active!
5 |
6 | pyro.collapsed_view.add = pyrotorque
7 |
8 | view.filter = pyrotorque, ((false))
9 | schedule2 = filter_pyrotorque, 1, 15,\
10 | "view.filter = pyrotorque,\"or={d.up.rate=,d.down.rate=,d.peers_connected=,not=$d.complete=}\""
11 |
12 | pyro.bind_key = pyrotorque_view, Q, "ui.current_view.set=pyrotorque"
13 |
14 | # TORQUE: Daemon watchdog
15 | method.insert = pyro.watchdog, simple|private,\
16 | "execute.nothrow=bash,-c,\"$cat=\\\"test ! -f \\\",$argument.0=,\\\"/run/pyrotorque || \\\",$pyro.bin_dir=,\\\"pyrotorque --cron \\\",$argument.1=, \\\" || true\\\"\""
17 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/view-datasize.rc:
--------------------------------------------------------------------------------
1 | ### UI/VIEW: Data size ######################################################
2 | # vim: ft=dosini
3 | # All items, sorted by their content size.
4 | # Bound to '"' key (will ONLY work if you use rT-PS)!
5 |
6 | pyro.collapsed_view.add = datasize
7 | pyro.bind_key = datasize_view, 0042, "view.sort = datasize ; ui.current_view.set = datasize"
8 |
9 | view.sort_new = datasize, "greater = d.size_bytes="
10 | view.sort_current = datasize, "greater = d.size_bytes="
11 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/view-indemand.rc:
--------------------------------------------------------------------------------
1 | ### UI/VIEW: Show items sorted by activity on "indemand" ####################
2 | # vim: ft=dosini
3 |
4 | pyro.collapsed_view.add = indemand
5 | pyro.bind_key = indemand_view, ?, "view.sort = indemand ; ui.current_view.set = indemand"
6 |
7 | view.filter = indemand, ((d.is_open))
8 | view.filter_on = indemand, event.download.closed, event.download.opened
9 |
10 | schedule2 = sort_indemand, 22, 33, "view.filter = indemand, d.is_open= ; view.sort = indemand"
11 |
12 | branch = (and, (system.has, "compare="), (system.has, "d.custom.if_z=")), \
13 | "view.sort_new = indemand, \"compare=--+,d.timestamp.last_active=,pyro._view_sort_timestamp=,d.name=\"", \
14 | "view.sort_new = indemand, greater=d.timestamp.last_active="
15 |
16 | branch = (and, (system.has, "compare="), (system.has, "d.custom.if_z=")), \
17 | "view.sort_current = indemand, \"compare=--+,d.timestamp.last_active=,pyro._view_sort_timestamp=,d.name=\"", \
18 | "view.sort_current = indemand, greater=d.timestamp.last_active="
19 |
20 | branch = (system.has, "convert.time_delta="), \
21 | "method.set_key = ui.column.render, \"968:6C21/1C28/1C21/2C28/2:◷ ℞ \", \
22 | ((if, ((d.peers_connected)), ((cat, \" \", ((convert.magnitude, ((d.peers_connected)) )), \"℞ \")), \
23 | ((convert.time_delta, ((value, ((d.timestamp.last_active)) )) )) ))", \
24 | ((print, "WARNING: No LAST ACTIVE column (update rTorrent-PS)!"))
25 |
26 | branch = (system.has, "ui.column.hide="), \
27 | ((ui.column.hide, 968)), \
28 | ((print, "WARNING: LAST ACTIVE column is static (update rTorrent-PS)!"))
29 |
30 | branch = (and, (system.has, "string.equals="), (system.has, "ui.column.hide=")), \
31 | "method.set_key = event.view.show, ~last_active_toggle, \
32 | \"branch = \\\"string.equals=$ui.current_view=, indemand, last_xfer, seeding\\\", \
33 | ui.column.show=968, ui.column.hide=968\""
34 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/view-last_xfer.rc:
--------------------------------------------------------------------------------
1 | ### UI/VIEW: Last data transfer #############################################
2 | # vim: ft=dosini
3 | #
4 | # All items, sorted by their last_xfer + active timestamps, or event times.
5 | #
6 | # Bound to '¬' key – will ONLY work if you use rT-PS!
7 | # (You might need to add another key bind, this works in Europe) ☺
8 | #
9 | # Note that to re-sort items, you have to select the view again (no auto-update).
10 | #
11 |
12 | pyro.collapsed_view.add = last_xfer
13 | pyro.bind_key = last_xfer_view, 0254, "view.sort = last_xfer ; ui.current_view.set = last_xfer"
14 |
15 | branch = (and, (system.has, "compare="), (system.has, "d.custom.if_z=")), \
16 | "view.sort_new = last_xfer, \"compare=---+,d.timestamp.last_xfer=,d.timestamp.last_active=,pyro._view_sort_timestamp=,d.name=\"", \
17 | "view.sort_new = last_xfer, greater=d.timestamp.last_xfer="
18 |
19 | branch = (and, (system.has, "compare="), (system.has, "d.custom.if_z=")), \
20 | "view.sort_current = last_xfer, \"compare=---+,d.timestamp.last_xfer=,d.timestamp.last_active=,pyro._view_sort_timestamp=,d.name=\"", \
21 | "view.sort_current = last_xfer, greater=d.timestamp.last_xfer="
22 |
23 | branch = (and, (system.has, "convert.time_delta="), (system.has, "d.custom.if_z=")), \
24 | "method.set_key = ui.column.render, \"962:6C21/1C23/1C21/2C23/2:◷ ↑↓ \", \
25 | ((convert.time_delta, ((value, ((d.custom.if_z, last_xfer, ((d.timestamp.last_active)) )) )) ))", \
26 | ((print, "WARNING: No LAST XFER column (update rTorrent-PS)!"))
27 |
28 | branch = (system.has, "ui.column.hide="), \
29 | ((ui.column.hide, 962)), \
30 | ((print, "WARNING: LAST XFER column is static (update rTorrent-PS)!"))
31 |
32 | branch = (and, (system.has, "string.equals="), (system.has, "ui.column.hide=")), \
33 | "method.set_key = event.view.show, ~last_xfer_toggle, \
34 | \"branch = \\\"string.equals=$ui.current_view=, last_xfer, started, seeding, leeching\\\", \
35 | ui.column.show=962, ui.column.hide=962\""
36 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/view-messages.rc:
--------------------------------------------------------------------------------
1 | ### UI/VIEW: Show current messages (bound to '!' in rT-PS) ##################
2 | # vim: ft=dosini
3 |
4 | pyro.collapsed_view.add = messages
5 | view.filter = messages, ((d.message))
6 |
7 | branch=pyro.extended=,false=,"view.sort_new = messages,less=d.message="
8 | branch=pyro.extended=,"view.sort_new = messages,\"compare=,d.message=,d.name=\""
9 |
10 | branch=pyro.extended=,false=,"view.sort_current = messages,less=d.message="
11 | branch=pyro.extended=,"view.sort_current = messages,\"compare=,d.message=,d.name=\""
12 |
13 | method.insert = pyro.ui.messages.show, simple,\
14 | "ui.current_view.set=messages ;view.sort=messages ;print=$view.size=messages,\" message(s)!\""
15 |
16 | pyro.bind_key = messages_view, !, "pyro.ui.messages.show="
17 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/view-ratio.rc:
--------------------------------------------------------------------------------
1 | ### UI/VIEW: Ratio ##########################################################
2 | # vim: ft=dosini
3 | # All items, sorted by their current ratio, upload size, or event times.
4 | # Bound to '%' key (will ONLY work if you use rT-PS)!
5 |
6 | pyro.collapsed_view.add = ratio
7 | pyro.bind_key = ratio_view, %, "view.sort = ratio ; ui.current_view.set = ratio"
8 |
9 | branch = (and, (system.has, "compare="), (system.has, "d.custom.if_z=")), \
10 | "view.sort_new = ratio, \"compare=---+,d.ratio=,d.up.total=,pyro._view_sort_timestamp=,d.name=\"", \
11 | "view.sort_new = ratio, greater=d.ratio="
12 |
13 | branch = (and, (system.has, "compare="), (system.has, "d.custom.if_z=")), \
14 | "view.sort_current = ratio, \"compare=---+,d.ratio=,d.up.total=,pyro._view_sort_timestamp=,d.name=\"", \
15 | "view.sort_current = ratio, greater=d.ratio="
16 |
17 | branch = (system.has, "string.substr="), \
18 | "method.set_key = ui.column.render, \"922:7C93/7: ☯ ‰ \", \
19 | ((string.substr, ((cat, \" \", ((d.ratio)) )), -6))", \
20 | ((print, "WARNING: No RATIO column (update rTorrent-PS)!"))
21 |
22 | branch = (system.has, "ui.column.hide="), \
23 | ((ui.column.hide, 922)), \
24 | ((print, "WARNING: RATIO column is static (update rTorrent-PS)!"))
25 |
26 | branch = (and, (system.has, "string.equals="), (system.has, "ui.column.hide=")), \
27 | "method.set_key = event.view.show, ~ratio_toggle, \
28 | \"branch = \\\"string.equals=$ui.current_view=, ratio, stopped\\\", \
29 | ui.column.show=922, ui.column.hide=922\""
30 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/view-tagged.rc:
--------------------------------------------------------------------------------
1 | ### UI/VIEW: Manually tag (select) items ####################################
2 | # vim: ft=dosini
3 | # . = toggle focused item between tagged and untagged
4 | # T = clear all tags
5 | # : = show tagged items view
6 |
7 | pyro.collapsed_view.add = tagged
8 | view.persistent = tagged
9 |
10 | # pyro.view.toggle_visible = ‹viewname› – Toggle visibility of an item for the given view
11 | method.insert = pyro.view.toggle_visible, simple|private,\
12 | "branch=d.views.has=$argument.0=,view.set_not_visible=$argument.0=,view.set_visible=$argument.0="
13 |
14 | # Empty the 'tagged' view, and remove visibility for all items
15 | method.insert = pyro._view_tagged_clear, simple|private,\
16 | "view.filter=tagged,false= ; d.multicall2 = default, d.views.remove=tagged"
17 |
18 | # Key bindings for 'tagged' view management
19 | pyro.bind_key = tagged_toggle, ., "pyro.view.toggle_visible=tagged"
20 | pyro.bind_key = tagged_clear, T, "pyro._view_tagged_clear="
21 | pyro.bind_key = tagged_view, :, "ui.current_view.set=tagged"
22 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/view-trackers.rc:
--------------------------------------------------------------------------------
1 | #### UI/VIEW: Trackers ######################################################
2 | # vim: ft=dosini
3 | # All items, sorted by tracker and name.
4 | # This will ONLY work if you use rT-PS!
5 |
6 | pyro.collapsed_view.add = trackers
7 | pyro.bind_key = trackers_view, t, "ui.current_view.set = trackers"
8 |
9 | branch = (system.has, "d.tracker_alias="), ((do, \
10 | "view.sort_new = trackers, \"compare=++, d.tracker_alias=, d.name=\"", \
11 | "view.sort_current = trackers, \"compare=++, d.tracker_alias=, d.name=\"" ))
12 |
13 | branch = (and, (pyro.extended), (not, (system.has, "d.tracker_alias="))), ((do, \
14 | "print = \"WARNING: Inferior sorting of 'trackers' view (update rTorrent-PS)!\"", \
15 | "view.sort_new = trackers, \"compare=++, d.tracker_domain=, d.name=\"", \
16 | "view.sort_current = trackers, \"compare=++, d.tracker_domain=, d.name=\"" ))
17 |
18 | branch = (system.has, "convert.time_delta="), \
19 | "method.set_key = ui.column.render, \"964:6C21/1C28/1C21/2C28/2:◷ ↺⤴⤵ \", \
20 | ((convert.time_delta, ((value, ((d.custom, tm_last_scrape)) )) ))", \
21 | ((print, "WARNING: No LAST SCRAPE column (update rTorrent-PS)!"))
22 |
23 | branch = (system.has, "ui.column.hide="), \
24 | ((ui.column.hide, 964)), \
25 | ((print, "WARNING: LAST SCRAPE column is static (update rTorrent-PS)!"))
26 |
27 | branch = (and, (system.has, "string.equals="), (system.has, "ui.column.hide=")), \
28 | "method.set_key = event.view.show, ~last_scrape_toggle, \
29 | \"branch = \\\"string.equals=$ui.current_view=, trackers, started, stopped\\\", \
30 | ((ui.column.show, 964)), \
31 | ((ui.column.hide, 964))\""
32 |
33 | branch = (system.has, "d.tracker_domain="), \
34 | "method.set_key = ui.column.render, \"966:?15:Domain\", \
35 | ((d.tracker_domain))"
36 |
37 | branch = (system.has, "ui.column.hide="), ((ui.column.hide, 966))
38 |
39 | branch = (and, (system.has, "string.equals="), (system.has, "ui.column.hide=")), \
40 | "method.set_key = event.view.show, ~trackets_domain_toggle, \
41 | \"branch = \\\"string.equals=$ui.current_view=, trackers\\\", \
42 | ((ui.column.show, 966)), \
43 | ((ui.column.hide, 966))\""
44 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/rtorrent.d/view-uploaded.rc:
--------------------------------------------------------------------------------
1 | ### UI/VIEW: Uploaded data ##################################################
2 | # vim: ft=dosini
3 | # All items, sorted by upload amount.
4 | # Bound to '°' key (will ONLY work if you use rT-PS)!
5 |
6 | pyro.collapsed_view.add = uploaded
7 | pyro.bind_key = uploaded_view, 0260, "view.sort = uploaded ; ui.current_view.set = uploaded"
8 |
9 | branch = (and, (system.has, "compare="), (system.has, "d.custom.if_z=")), \
10 | "view.sort_new = uploaded, \"compare=--+,d.up.total=,pyro._view_sort_timestamp=,d.name=\"", \
11 | "view.sort_new = uploaded, greater=d.up.total="
12 |
13 | branch = (and, (system.has, "compare="), (system.has, "d.custom.if_z=")), \
14 | "view.sort_current = uploaded, \"compare=--+,d.up.total=,pyro._view_sort_timestamp=,d.name=\"", \
15 | "view.sort_current = uploaded, greater=d.up.total="
16 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/templates/conky/conkyrc:
--------------------------------------------------------------------------------
1 | # Sample conky Configuration
2 | #
3 | # The settings below are just for demo purposes
4 | # Integrate the TEXT portion into your normal ~/.conkyrc
5 | #
6 | # Call it like so to see what it looks like:
7 | # pyroadmin --create-config
8 | # conky -c ~/.pyroscope/templates/conky/conkyrc
9 |
10 | update_interval 5.0
11 | own_window yes
12 | own_window_transparent yes
13 | own_window_hints undecorated,below,skip_taskbar,skip_pager
14 | maximum_width 320
15 | minimum_size 320 600
16 | alignment top_right
17 |
18 | default_shade_color 999999
19 | default_outline_color 222222
20 | draw_outline yes
21 | draw_shades yes
22 |
23 | use_xft yes
24 | xftfont Lucida Sans Typewriter:size=8
25 | #xftfont Bitstream Vera Sans Mono:size=8
26 | xftalpha 0.8
27 |
28 | background yes
29 | double_buffer yes
30 | total_run_times 0
31 | override_utf8_locale yes
32 | text_buffer_size 16768
33 |
34 | TEXT
35 | ${execpi 5 ~/bin/rtcontrol -qO conky/rtorstat.txt --from-view incomplete is_open=yes is_ignored=no}
36 |
37 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/templates/conky/rtorstat.txt:
--------------------------------------------------------------------------------
1 | {{# Template example for conky that is similar to the rtorstat output.
2 |
3 | See the conkyrc file, and http://www.codetrax.org/projects/rtorstat
4 | }}{{py:
5 | global os, time, subprocess, incomplete, active, max_entries, viewdef, df
6 | import time
7 | import subprocess
8 | from pyrocore.util import os
9 |
10 | viewdef = [i.split() for i in (
11 | "i main",
12 | "< stopped",
13 | "6 incomplete",
14 | "5 active",
15 | )]
16 |
17 | df = os.statvfs(proxy.directory.default())
18 | df = df.f_bavail * df.f_bsize
19 |
20 | max_entries = 4
21 | incomplete = [i for i in matches if not i.is_complete]
22 | active = [] #[i for i in matches if i.is_complete]
23 | }}{{#
24 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 | }}{{def color(c, s)}}${color {{c}}}{{s}}${color }{{enddef}}{{#
26 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27 | }}{{def header(s)}}{{color('#9bf', s)}}{{enddef}}{{#
28 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29 | }}{{def label(s)}}{{color('#66d', s)}}{{enddef}}{{#
30 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31 | }}{{def pc_col(f)}}${color #{{('f00','f33','f63','3c9','3fc')[min(4, int(f/25))]}}}{{enddef}}{{#
32 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
33 | }}{{def show(loop, d)}}{{#
34 | }}{{"%2d." % loop.number|label}} {{d.name}} {{'['|label}}{{d.alias}}{{']'|label}}
35 | {{'S'|label}} {{d.size|sz}} {{'U'|label}} {{d.uploaded|sz}} {{'R'|label}} {{pc_col(d.ratio*100.0)}}{{d.ratio|pc}}%${color }{{#
36 | }}{{enddef}}{{#
37 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
38 | }}{{'rTorrent'|header}} {{'VERSION %CPU %MEM UPTIME'|label}}
39 | {{"%-13.13s" % proxy.session.name()}} {{"%-8s" % proxy.system.client_version()}}{{#
40 | }} {{subprocess.Popen(["ps", "h", "-o", "%cpu,%mem,etime", "-p", str(proxy.system.pid())], stdout=subprocess.PIPE).communicate()[0].rstrip()}}
41 |
42 | {{'Views '|header}} {{for title, name in viewdef}} {{str(proxy.view.size('', name)).ljust(5)}} {{endfor}}
43 | ${voffset -14} ${font Webdings:size=12}{{for title, name in viewdef}}{{title|label}} {{endfor}}${font }
44 | ${voffset 4}{{'Data '|header}} {{'U'|label}}{{proxy.throttle.global_up.total()|sz}} {{'D'|label}}{{proxy.throttle.global_down.total()|sz}}{{#
45 | }} {{'F'|label}}{{df|sz}}
46 | {{'Upload '|label}} {{"%3.0f" % (100.0 * proxy.throttle.global_up.rate() / proxy.throttle.global_up.max_rate())}}% {{#
47 | }}${color #0d6}${execgraph echo {{min(100, 100.0 * proxy.throttle.global_up.rate() / proxy.throttle.global_up.max_rate())}}}${color }
48 | ${voffset -20} {{proxy.throttle.global_up.rate()|sz}}/s
49 | {{pc_col(100.0 * proxy.throttle.global_up.rate() / proxy.throttle.global_up.max_rate())}} ${execbar echo {{min(100, 100.0 * proxy.throttle.global_up.rate() / proxy.throttle.global_up.max_rate())}}}${color }
50 | {{'Download'|label}} {{"%3.0f" % (100.0 * proxy.throttle.global_down.rate() / proxy.throttle.global_down.max_rate())}}% {{#
51 | }}${color #d06}${execgraph echo {{min(100, 100.0 * proxy.throttle.global_down.rate() / proxy.throttle.global_down.max_rate())}}}${color }
52 | ${voffset -20} {{proxy.throttle.global_down.rate()|sz}}/s
53 | {{pc_col(100.0 * proxy.throttle.global_down.rate() / proxy.throttle.global_down.max_rate())}} ${execbar echo {{min(100, 100.0 * proxy.throttle.global_down.rate() / proxy.throttle.global_down.max_rate())}}}${color }
54 | {{if incomplete}}
55 |
56 | {{'Incomplete'|header}} {{'['|label}}{{len(incomplete)}}{{']'|label}}
57 | {{for loop, d in looper(incomplete[:max_entries])}}
58 | {{show(loop, d)}} {{'D'|label}} {{d.down|sz}}/s
59 | {{pc_col(d.done)}}{{"%5.1f" % d.done}}% ${execbar echo {{d.done}}}${color }
60 | {{endfor}}
61 | {{endif}}
62 | {{for i in range(3*len(incomplete), 3*max_entries)}}
63 | {{' ' * 53}}
64 | {{endfor}}
65 | {{if active}}
66 |
67 | {{'Active'|header}} {{'['|label}}{{len(active)}}{{']'|label}}
68 | {{for loop, d in looper(active[:max_entries])}}
69 | {{show(loop, d)}}
70 | {{endfor}}
71 | {{endif}}
72 | ${font Verdana:slant=italic:size=6}${color #666}PyroScope {{version}} at {{time.time() | iso}} ${color }${font }
73 | {{#EOF}}
74 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/templates/irc_status.txt:
--------------------------------------------------------------------------------
1 | {{# Template example that generates a short status display suitable for the shell or IRC.
2 |
3 | Use it like this:
4 | rtcontrol -qO irc_status.txt //
5 |
6 | }}{{py:
7 | import time
8 | }}rTorrent {{proxy.system.client_version()}}/{{proxy.system.library_version()}} - {{#
9 | }}up {{(time.time() - proxy.system.startup_time()) | duration}} - {{view.size()}} items
10 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/templates/json:
--------------------------------------------------------------------------------
1 | {{# This template serializes the result into JSON.
2 |
3 | Use it like this:
4 | rtcontrol -qOjson //
5 | }}[
6 | {{for loop, item in looper(matches)}}{{item.as_dict() | json}}{{if not loop.last}},
7 | {{endif}}{{endfor}}
8 | ]
9 | {{#}}
10 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/templates/orphans.txt:
--------------------------------------------------------------------------------
1 | {{# This template lists all paths in the given directory
2 | (or the download directory) NOT loaded into the client.
3 |
4 | Use it like this:
5 | rtcontrol -qO orphans.txt.default // -Ddir=$PWD
6 | }}{{py:
7 | global os, config, checked_dir, entries
8 | from pyrocore import config
9 | from pyrocore.util import os
10 |
11 | checked_dir = os.path.expanduser(getattr(config, 'dir', proxy.directory.default()))
12 | checked_dir = os.path.realpath(checked_dir.rstrip(os.sep)) + os.sep
13 |
14 | # List all non-symlinked entries in given directory
15 | entries = set(i.decode('utf8')
16 | for i in os.listdir(checked_dir)
17 | if not os.path.islink(os.path.join(checked_dir, i)))
18 |
19 | # From that list, remove anything loaded in the client
20 | entries -= set(os.path.basename(d.realpath)
21 | for d in matches
22 | if d.realpath.startswith(checked_dir))
23 | }}{{for i in sorted(entries)}}{{#
24 | }}{{checked_dir}}{{i}}
25 | {{endfor}}
26 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/templates/rss.xml:
--------------------------------------------------------------------------------
1 | {{# Template that creates a RSS feed from matched items.
2 |
3 | First, install additional requirements:
4 |
5 | python-pyrocore -m pip install feedgen pytz tzlocal
6 |
7 | Then use this command to generate the feed:
8 |
9 | rtcontrol -qO rss.xml.default --from incomplete //
10 |
11 | Finally put it into a CGI script, or write to a file in
12 | the "htdocs" directory of a webserver, from a cronjob.
13 | }}{{py:
14 | import datetime
15 | from feedgen.feed import FeedGenerator
16 | #from pytz import utc as tz
17 | from tzlocal import get_localzone
18 | tz = get_localzone()
19 |
20 | feed = FeedGenerator()
21 | name = ':'.join(proxy.session.name().split())
22 | feed.id(name)
23 | feed.title('rTorrent %s - incomplete items' % name)
24 | feed.link(href='https://www.reddit.com/r/torrents/comments/f8cy7l')
25 | feed.description('%d incomplete item(s) in this feed.' % len(matches))
26 |
27 | for item in matches:
28 | entry = feed.add_entry()
29 | entry.guid(item.hash)
30 | entry.published(datetime.datetime.fromtimestamp(item.loaded, tz=tz))
31 | entry.title('%s [%s - %d%%]' % (item.name, item.alias, item.done))
32 | entry.summary('%.3f GiB - R %.1f%% - %s' % (
33 | item.size / (1024.0**3), item.ratio, ' '.join(item.traits),
34 | ))
35 | }}{{ feed.rss_str(pretty=True) }}
36 |
--------------------------------------------------------------------------------
/src/pyrocore/data/config/templates/rtorstat.html:
--------------------------------------------------------------------------------
1 | {{# Template example that is similar to the rtorstat output.
2 |
3 | See http://www.codetrax.org/projects/rtorstat
4 |
5 | Use it in a cronjob like this:
6 | rtcontrol -qO rtorstat.html done=-100 OR xfer=+0 -sdone >/var/www/cron/rtorrent.html
7 | }}{{py:
8 | import time
9 | }}{{def title}}
10 | rTorrent {{proxy.system.client_version()}}/{{proxy.system.library_version()}}
11 | - {{proxy.session.name()}}
12 | - up {{(time.time() - proxy.system.startup_time()) | duration}}
13 | {{enddef}}{{def show(loop, d)}}
14 |
15 | {{loop.number}}.
{{d.name}} (
{{d.alias}})
16 |
17 |
{{"%.1f" % d.done}}%
18 |
19 | size: {{d.size|sz}} - uploaded: {{d.uploaded|sz}} - ratio: {{d.ratio|pc}}%
20 |
21 | {{enddef}}
22 |
23 |
24 |
25 |
26 |
27 |
28 | {{title}}
29 |
30 |
70 |
71 |
72 | {{title}}
73 |
74 | Query
75 | Selected {{len(matches)}} out of {{view.size()}} items using "{{query}}".
76 |
77 | Incomplete
78 | {{for loop, d in looper(i for i in matches if not i.is_complete)}}
79 | {{show(loop, d)}}
80 | {{endfor}}
81 |
82 | Active
83 | {{for loop, d in looper(i for i in matches if i.is_complete)}}
84 | {{show(loop, d)}}
85 | {{endfor}}
86 |
87 |
88 | Created by PyroScope {{version}} at {{time.time() | iso}}
89 |
90 |
91 |
92 |