├── debian ├── compat ├── links ├── install ├── watch ├── rules ├── copyright ├── control ├── changelog └── bash_completion │ └── termsaver ├── tests ├── empty-for-tests │ └── testfile.txt └── test.py ├── extras ├── termsaver-sysmon.jpg ├── termsaver-main_medium.jpeg ├── upload_dist.sh ├── deb_package.sh ├── update_l10n.sh ├── ubuntu_package.sh └── README.dist ├── termsaver ├── __main__.py └── termsaverlib │ ├── screen │ ├── clocknumber for tremsaver.xlsm │ ├── helper │ │ ├── __init__.py │ │ ├── typing.py │ │ ├── imageconverter.py │ │ ├── xmlreader.py │ │ └── urlfetcher.py │ ├── urlfetcher.py │ ├── wttr.py │ ├── asciiartfarts.py │ ├── __init__.py │ ├── rssfeed.py │ ├── rfc.py │ ├── programmer.py │ ├── jokes4all.py │ ├── quotes4all.py │ ├── starwars.py │ ├── base │ │ ├── urlfetcher.py │ │ └── rssfeed.py │ └── randtxt.py │ ├── plugins │ ├── exampleplugin │ │ ├── screen │ │ │ ├── __init__.py │ │ │ ├── base │ │ │ │ └── __init__.py │ │ │ └── eps.py │ │ └── constants.py │ └── __init__.py │ ├── helper │ ├── __init__.py │ ├── smartformatter.py │ └── utilities.py │ ├── __init__.py │ ├── i18n.py │ ├── constants.py │ ├── exception.py │ └── common.py ├── locale ├── en │ └── LC_MESSAGES │ │ └── termsaver.mo ├── ja │ └── LC_MESSAGES │ │ ├── termsaver.mo │ │ └── termsaver.po └── pt │ └── LC_MESSAGES │ └── termsaver.mo ├── .settings └── org.eclipse.core.resources.prefs ├── completion ├── termsaver-completion.bash └── _termsaver ├── FAQ.md ├── pyproject.toml ├── CHANGELOG ├── TODO ├── MANIFEST.in ├── .project ├── .gitignore ├── .pydevproject ├── doc └── termsaver.1 └── README.md /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /tests/empty-for-tests/testfile.txt: -------------------------------------------------------------------------------- 1 | This is a test file! -------------------------------------------------------------------------------- /debian/links: -------------------------------------------------------------------------------- 1 | /usr/share/termsaver/termsaver /usr/bin/termsaver 2 | -------------------------------------------------------------------------------- /debian/install: -------------------------------------------------------------------------------- 1 | debian/bash_completion/termsaver etc/bash_completion.d/ -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=3 2 | http://pypi.python.org/packages/source/t/termsaver/termsaver-(.+).tar.gz 3 | -------------------------------------------------------------------------------- /extras/termsaver-sysmon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunobraga/termsaver/HEAD/extras/termsaver-sysmon.jpg -------------------------------------------------------------------------------- /termsaver/__main__.py: -------------------------------------------------------------------------------- 1 | from termsaver import entryPoint 2 | 3 | if __name__ == '__main__': 4 | entryPoint() -------------------------------------------------------------------------------- /extras/termsaver-main_medium.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunobraga/termsaver/HEAD/extras/termsaver-main_medium.jpeg -------------------------------------------------------------------------------- /locale/en/LC_MESSAGES/termsaver.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunobraga/termsaver/HEAD/locale/en/LC_MESSAGES/termsaver.mo -------------------------------------------------------------------------------- /locale/ja/LC_MESSAGES/termsaver.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunobraga/termsaver/HEAD/locale/ja/LC_MESSAGES/termsaver.mo -------------------------------------------------------------------------------- /locale/pt/LC_MESSAGES/termsaver.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunobraga/termsaver/HEAD/locale/pt/LC_MESSAGES/termsaver.mo -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//termsaverlib/screen/matrix.py=utf-8 3 | encoding//termsaverlib/screen/sysmon.py=utf-8 4 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/clocknumber for tremsaver.xlsm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunobraga/termsaver/HEAD/termsaver/termsaverlib/screen/clocknumber for tremsaver.xlsm -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | override_dh_auto_install: 5 | dh_auto_install -- --install-lib=/usr/share/termsaver --install-script=/usr/share/termsaver 6 | 7 | %: 8 | dh $@ --with python3,bash_completion 9 | 10 | -------------------------------------------------------------------------------- /completion/termsaver-completion.bash: -------------------------------------------------------------------------------- 1 | _termsaver () { 2 | local cur prev opts 3 | COMPREPLY=() 4 | cur="${COMP_WORDS[COMP_CWORD]}" 5 | prev="${COMP_WORDS[COMP_CWORD-1]}" 6 | if [[ ${cur} == -* ]]; then 7 | opts="--help --verbose" 8 | else 9 | opts="asciiartfarts clock img2ascii jokes4all matrix programmer quotes4all randtxt rfc rssfeed urlfetcher starwars sysmon" 10 | fi 11 | COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) && return 0 12 | } 13 | complete -F _termsaver termsaver 14 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | # Frequently Asked Questions 2 | 3 | Q: A receive the error "AttributeError: module 'collections' has no attribute 'MutableMapping'. 4 | 5 | A: Your system likely has an out of date essential package, like pip, wheel, or setuptools. Try upgrading them with the following command: `pip install --upgrade pip wheel setuptools requests` 6 | 7 | Q: After installing `termsaver` I get a `command not found` error. 8 | 9 | A: Depending on your distro, your packages might have been installed to ~/.local/bin. Please add this path to your PATH. e.g. `export PATH=$PATH:/home//.local/bin` 10 | 11 | If you have a question that is not answered here, please submit an issue on GitHub and we'll be happy to add it if applicable. -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by Bruno Braga on 2 | Fri, 13 Apr 2012 15:12:10 +0000 3 | 4 | Upstream Author: Bruno Braga 5 | 6 | Contributor(s): 7 | Shelby Jueden 8 | Alexander Riccio 9 | Eddie Dover 10 | 11 | Copyright: 12 | 13 | 14 | 15 | License: 16 | 17 | This software is licensed under the Apache License 2.0. On Debian 18 | GNU/Linux systems you can find the complete text of the Apache-2.0 19 | license in `/usr/share/common-licenses/Apache-2.0'. 20 | 21 | The Debian package is (C) 2011-2020, Bruno Braga 22 | and is licensed under the Apache License 2.0, see above. 23 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.pdm] 2 | 3 | [project] 4 | name = "termsaver" 5 | version = "0.7" 6 | description = "Simple text-based terminal screensaver." 7 | keywords = ["command-line", "terminal", "screensaver"] 8 | readme = "README.md" 9 | authors = [ 10 | {name = "Bruno Braga", email = "bruno@brunobraga.net"}, 11 | ] 12 | maintainers = [ 13 | {name = "Eddie Dover", email = "ed@eddiedover.dev"}, 14 | ] 15 | requires-python = ">=3.12" 16 | dependencies = [ 17 | "pillow", 18 | "requests", 19 | ] 20 | license = {text = "Apache License v2"} 21 | 22 | [project.urls] 23 | Homepage = "https://www.github.com/brunobraga/termsaver" 24 | "Bug Tracker" = "https://github.com/brunobraga/termsaver/issues" 25 | 26 | [project.scripts] 27 | termsaver = "termsaver:entryPoint" 28 | 29 | [build-system] 30 | requires = ["pdm-backend"] 31 | build-backend = "pdm.backend" 32 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: termsaver 2 | Section: misc 3 | Priority: optional 4 | Maintainer: Bruno Braga 5 | Uploaders: Python Applications Packaging Team 6 | Build-Depends: debhelper (>= 7.4.3), python, bash-completion 7 | X-Python-Version: >= 2.5 8 | Standards-Version: 3.9.3 9 | Vcs-Svn: svn://anonscm.debian.org/python-apps/packages/termsaver/trunk/ 10 | Vcs-Browser: http://anonscm.debian.org/viewvc/python-apps/packages/termsaver/trunk/ 11 | Homepage: http://termsaver.brunobraga.net 12 | 13 | Package: termsaver 14 | Architecture: all 15 | Depends: ${misc:Depends}, ${python:Depends} 16 | Description: simple text-based terminal screensaver 17 | termsaver is a very simple project that aims at bringing 18 | the feel of a screensaver feature in text-based terminal 19 | environment. 20 | . 21 | there are many screens that can be chosen and customized 22 | with command-line options, and the application has been 23 | developed to accept future plugins to additional screens. 24 | 25 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: CHANGELOG 4 | # 5 | # Purpose: holds major milestone changes and version update contents. 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | 28 | See file debian/changelog 29 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: TODO 4 | # 5 | # Purpose: holds ideas for improvement or pending accepted bugs. 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | 28 | Refer to https://github.com/brunobraga/termsaver/wiki/Brainstorming 29 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/plugins/exampleplugin/screen/__init__.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: __init__.py 4 | # 5 | # Purpose: refer to package documentation for details 6 | # 7 | # Note: This file is part of Termsaver-ExamplePlugin plugin, and should not be 8 | # used or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | """ 29 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: MANIFEST.in 4 | # 5 | # Purpose: required for python packaging 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | 28 | # 29 | # Add l10n files to package 30 | # 31 | recursive-include locale completion *.mo 32 | 33 | include termsaver/data/* -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | termsaver (0.4-1) unstable; urgency=low 2 | 3 | * Added zsh completion (wkentaro). 4 | * Implemented sysmon for MacOS. 5 | 6 | 7 | -- Bruno Braga Wed, 18 Jul 2018 14:11:00 +1000 8 | 9 | termsaver (0.3-1) unstable; urgency=low 10 | 11 | * Improved programmer screen by placing file search in background. 12 | 13 | 14 | -- Bruno Braga Tue, 02 Mar 2014 19:42:01 +1000 15 | 16 | termsaver (0.2-2) UNRELEASED; urgency=low 17 | 18 | * Use canonical URIs for Vcs-* fields. 19 | 20 | -- Jakub Wilk Sun, 05 May 2013 18:05:52 +0200 21 | 22 | termsaver (0.2-1) unstable; urgency=low 23 | 24 | * Fixed syntax for python 2.5 support. 25 | * Fixed small char bug on clock screen. 26 | * Fixed issue for longer words in random text screen. 27 | * Removed HTML tags from RSS feeds screen. 28 | * Other improvements in the code (screen geometry, etc). 29 | * added sysmon screen, and deprecated dot screen. 30 | 31 | -- Bruno Braga Tue, 15 Mar 2013 22:08:22 +1000 32 | 33 | termsaver (0.1.1-1) unstable; urgency=low 34 | 35 | * Packaging work for initial inclusion in Debian. (Closes: #668618) 36 | 37 | -- Bruno Braga Thu, 14 Apr 2012 23:26:01 +1000 38 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/helper/__init__.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: __init__.py 4 | # 5 | # Purpose: refer to package documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This package holds all helper classes used by termsaverlib, to add 29 | reusable functionality to them, and help maintain consistency throughout all 30 | of them. 31 | """ 32 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/helper/smartformatter.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: smartformatter.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | import argparse 28 | import sys 29 | 30 | class SmartFormatter(argparse.ArgumentDefaultsHelpFormatter): 31 | 32 | def _split_lines(self, text, width): 33 | 34 | if text.startswith('R|'): 35 | text = text[2:] 36 | return text.split_lines(self,text,width) 37 | 38 | return argparse.ArgumentDefaultsHelpFormatter._split_lines(self, text, width) 39 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/helper/utilities.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: utilities.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | import sys 28 | 29 | 30 | def hide_stdout_cursor(): 31 | sys.stdout.write("\033[?25l") 32 | 33 | def show_stdout_cursor(): 34 | sys.stdout.write('\033[?25h') 35 | 36 | def hide_cursor(): 37 | """ 38 | Hides the cursor. 39 | """ 40 | print("\033[?25l", end="") 41 | 42 | def show_cursor(): 43 | """ 44 | Shows the cursor. 45 | """ 46 | print('\033[?25h', end="") -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 30 | 31 | termsaver 32 | 33 | 34 | 35 | 36 | 37 | org.python.pydev.PyDevBuilder 38 | 39 | 40 | 41 | 42 | 43 | org.python.pydev.pythonNature 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: .gitignore 4 | # 5 | # Purpose: Forces GIT to ignore certain files when commiting changes. 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | 28 | # compiled files 29 | *.py[co] 30 | #*.mo 31 | 32 | # Packages 33 | *.egg 34 | *.egg-info 35 | dist 36 | build 37 | eggs 38 | parts 39 | bin 40 | var 41 | sdist 42 | develop-eggs 43 | .installed.cfg 44 | 45 | # Installer logs 46 | pip-log.txt 47 | 48 | # Unit test / coverage reports 49 | .coverage 50 | .tox 51 | 52 | # Source Code Cache 53 | termsaver_cache.list 54 | .wakatime-project 55 | 56 | dev_env/ 57 | .vscode/launch.json 58 | .pdm-python 59 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 31 | 32 | Default 33 | python 2.7 34 | 35 | /termsaver 36 | /termsaver/termsaverlib 37 | 38 | 39 | -------------------------------------------------------------------------------- /extras/upload_dist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################### 3 | # 4 | # file: upload_dist.sh 5 | # 6 | # Purpose: Upload this application to Python distribution channel. 7 | # 8 | # Note: This file is part of Termsaver application, and should not be used 9 | # or executed separately. 10 | # 11 | ############################################################################### 12 | # 13 | # Copyright 2012 Termsaver 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 16 | # not use this file except in compliance with the License. You may obtain 17 | # a copy of the License at 18 | # 19 | # http://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 23 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 24 | # License for the specific language governing permissions and limitations 25 | # under the License. 26 | # 27 | ############################################################################### 28 | 29 | echo "Cleaning up previous actions..." 30 | rm -rvf ./README ./dist ./build ./MANIFEST termsaver.egg-info/ 31 | 32 | # 33 | # Bring the dist README file for uploading process 34 | # 35 | echo "Copying distribution README file to root directory..." 36 | cp -vf extras/README.dist ./README 37 | 38 | echo "Registering user..." 39 | python setup.py register 40 | 41 | echo "Executing python source distribution upload..." 42 | python setup.py sdist upload 43 | 44 | # Done! 45 | echo "Done" 46 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/__init__.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: __init__.py 4 | # 5 | # Purpose: refer to python doc for documentation details. 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This module holds all stuff required for termsaver application to work properly 29 | 30 | The modules available in this package are: 31 | 32 | * `common`: helper functions used by termsaver code 33 | 34 | * `constants`: series of configuration constants used by termsaver code 35 | 36 | * `exceptions`: various exceptions classes to handle termsaver errors 37 | 38 | * `i18n`: handles internationalization for termsaver application 39 | 40 | This also contains the following sub-packages: 41 | 42 | * `screen`: holds all screens accessible by termsaver application. Also 43 | holds base and helper classes to ease the implementation of new screens. 44 | """ 45 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/i18n.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: i18n.py 4 | # 5 | # Purpose: refer to python doc for documentation details. 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | Handles all internationalization (i18n) functionality for termsaver application 29 | """ 30 | 31 | # 32 | # Python build-in modules 33 | # 34 | import gettext 35 | 36 | # 37 | # Internal modules 38 | # 39 | from termsaver.termsaverlib import constants 40 | 41 | _ = None 42 | """ 43 | The unicode text dealer for i18n stuff, renamed as an underscore to keep same 44 | standards used by gettext. 45 | """ 46 | 47 | 48 | def set_app(application_name): 49 | """ 50 | Defines the application name for the binding text files. 51 | """ 52 | result = None 53 | 54 | try: 55 | gettext.textdomain(application_name) 56 | result = gettext.gettext 57 | except: 58 | # 59 | # If we can not handle i18n, just deal with text as it is 60 | # 61 | result = lambda x: x 62 | 63 | # For debugging 64 | #raise 65 | 66 | return result 67 | 68 | # 69 | # Call the default (termsaver app name) 70 | # 71 | _ = set_app(constants.App.NAME) 72 | # 73 | # This should be overriden by plugins, as they can have their own i18n files 74 | # -------------------------------------------------------------------------------- /extras/deb_package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################### 3 | # 4 | # file: deb_package.sh 5 | # 6 | # Purpose: Prepares and builds DEB packages. 7 | # 8 | # Note: This file is part of Termsaver application, and should not be used 9 | # or executed separately. 10 | # 11 | ############################################################################### 12 | # 13 | # Copyright 2012 Termsaver 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 16 | # not use this file except in compliance with the License. You may obtain 17 | # a copy of the License at 18 | # 19 | # http://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 23 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 24 | # License for the specific language governing permissions and limitations 25 | # under the License. 26 | # 27 | ############################################################################### 28 | 29 | 30 | # dependencies as of Ubuntu 18.04 LTS: python build-essential debhelper devscripts 31 | 32 | 33 | base_path="`pwd`/`dirname $0`/.." 34 | cur_dir=`pwd` 35 | 36 | function get_prop() { 37 | python -c "from termsaver.termsaverlib import constants; print constants.App.$@" 38 | } 39 | 40 | 41 | package_name=`get_prop "NAME"` 42 | package_version=`get_prop "VERSION"` 43 | 44 | temp_dir=/tmp/packaging/ 45 | package_dir_name=${package_name}_${package_version} 46 | 47 | echo "Removing old garbage..." 48 | rm -rfv $temp_dir 49 | echo "Done" 50 | 51 | echo "Creating temporary directory..." 52 | mkdir -p $temp_dir 53 | echo "Done" 54 | 55 | echo "Copying project..." 56 | cp -rfv $base_path $temp_dir/$package_dir_name 57 | echo "Done" 58 | 59 | cd $temp_dir/$package_dir_name 60 | 61 | echo "Cleaning up..." 62 | rm -rfv .git* 63 | echo "Done" 64 | 65 | echo "Making original tarball" 66 | mv debian ../ 67 | tar -czvf ../$package_dir_name.orig.tar.gz ../$package_dir_name 68 | mv ../debian . 69 | echo "Done" 70 | 71 | 72 | echo "Building package..." 73 | dpkg-buildpackage -rfakeroot 74 | echo "Done" 75 | 76 | cd $cur_dir 77 | 78 | # Done! 79 | echo "Finished packaging $package_dir_name" 80 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/plugins/exampleplugin/screen/base/__init__.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: __init__.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver-ExamplePlugin plugin, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This module holds base classes that are used by all screens within termsaver 29 | application. Each individual "screen" represents a unique screensaver that can 30 | be triggered by termsaver. 31 | 32 | The base classes available in this package are: 33 | 34 | * `ExamplePluginScreenBase`: the most basic screen class, which will handle simple 35 | interaction with the terminal. 36 | 37 | 38 | """ 39 | 40 | # 41 | # Python built-in modules 42 | # 43 | import os 44 | import textwrap 45 | 46 | from termsaver.termsaverlib import common, exception 47 | from termsaver.termsaverlib.i18n import _, set_app 48 | # 49 | # Internal modules 50 | # 51 | from termsaver.termsaverlib.screen.base import ScreenBase 52 | from termsaver.termsaverlib.screen.helper.position import PositionHelperBase 53 | 54 | # 55 | # Override termsavr default i18n (reuired for plugins with own i18n files) 56 | # 57 | set_app("termsaver-exampleplugin") 58 | 59 | class ExamplePluginScreenBase(ScreenBase, PositionHelperBase): 60 | """ 61 | """ 62 | 63 | def example_echo(self, echo_text): 64 | """ 65 | Just echos the incoming text 66 | """ 67 | return echo_text 68 | -------------------------------------------------------------------------------- /debian/bash_completion/termsaver: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # 3 | # file: termsaver 4 | # 5 | # Purpose: Bash auto-complete functionality for Termsaver. 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | 28 | have termsaver && _termsaver() 29 | { 30 | local cur prev opts plugin_opts 31 | cur="${COMP_WORDS[COMP_CWORD]}" 32 | prev="${COMP_WORDS[COMP_CWORD-1]}" 33 | opts="sysmon matrix asciiartfarts rssfeed urlfetcher quotes4all jokes4all clock randtxt rfc programmer" 34 | 35 | # For plugins adding new screens, you can append to the below area 36 | # with a line such as: 37 | # 38 | # plugin_opts=$plugin_opts" plugin-screen-1 ... plugin-screen-N" 39 | # 40 | # To patch this section, use sed: 41 | # sed -e 's:plugin_opts=$plugin_opts:plugin_opts=$plugin_opts" plugin-screen-1 ... plugin-screen-N":' 42 | # 43 | plugin_opts= 44 | # Plugin Appending: BEGIN 45 | 46 | plugin_opts=$plugin_opts 47 | 48 | # Plugin Appending: END 49 | 50 | # avoid repeating screens once one has been already selected 51 | # if [ `echo "$opts $plugin_opts" | grep -e "$prev" | wc -l` -eq 1 ]; then 52 | # return 0 53 | # fi 54 | if [ "$prev" == "-p" -o "$prev" == "--path" ]; then 55 | _filedir 56 | return 0 57 | fi 58 | 59 | # do not let options reappear once is it not direct previous 60 | if [ ! "${COMP_WORDS[1]}" == "$cur" -a ! "${COMP_WORDS[1]}" == "" -a `echo "$opts $plugin_opts" | grep -e "${COMP_WORDS[1]}" | wc -l` -eq 1 ]; then 61 | return 0 62 | fi 63 | 64 | COMPREPLY=( $( compgen -W "${opts}" -- "${cur}" ) ) 65 | if [[ ${#COMPREPLY[@]} == 1 && ${COMPREPLY[0]} != "--"*"=" ]] ; then 66 | # If there's only one option, without =, then allow a space 67 | compopt +o nospace 68 | fi 69 | return 0 70 | } && 71 | complete -o nospace -F _termsaver termsaver 72 | 73 | 74 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/helper/__init__.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: __init__.py 4 | # 5 | # Purpose: refer to package documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This package holds all helper classes used by termsaver screens, to add 29 | reusable functionality to them, and help maintain consistency throughout all 30 | of them. 31 | 32 | All helper screens should inherit from the base screen helper 33 | `ScreenHelperBase`, documented below. 34 | 35 | The available classes in this package are: 36 | 37 | * `ScreenHelperBase`: the main helper class from which all helper classes 38 | will inherit from. 39 | 40 | * `typing.TypingHelperBase`: helper functionality to display typing writer 41 | effects for screens. 42 | 43 | * `urlfetcher.URLFetcherHelperBase`: helper functionalities to give 44 | Internet connectivity to screens. 45 | 46 | * `xmlreader.XMLReaderHelperBase`: helper functionalities to assist on 47 | XML parsing. 48 | 49 | """ 50 | # 51 | # Python built-in modules 52 | # 53 | from os import system 54 | 55 | # 56 | # Internal modules 57 | # 58 | from termsaver.termsaverlib.common import is_windows 59 | 60 | 61 | class ScreenHelperBase(object): 62 | """ 63 | This is the main helper class from which all should inherit from. This 64 | will also hold most rudimentary functionalities that can be reused by 65 | all screens. 66 | """ 67 | 68 | @staticmethod 69 | def clear_screen(): 70 | """ 71 | A simple method that clears the screen. 72 | 73 | This supports both Windows and Unix base systems. 74 | """ 75 | if is_windows(): 76 | # Execute command for Windows Platform, DOS console 77 | __ = system('cls') # Windows prints the output of this call 78 | else: 79 | # Execute command for Unix based Platform 80 | system('clear') 81 | -------------------------------------------------------------------------------- /completion/_termsaver: -------------------------------------------------------------------------------- 1 | #compdef termsaver 2 | 3 | _termsaver () { 4 | local -a _1st_arguments 5 | _1st_arguments=( 6 | "asciiartfarts:displays ascii images from asciiartfarts.com (NSFW)" 7 | "clock:displays a digital clock on screen" 8 | "jokes4all:displays recent jokes from jokes4all.net (NSFW)" 9 | "matrix:displays a matrix movie alike screensaver" 10 | "programmer:displays source code in typing animation" 11 | "quotes4all:displays recent quotes from quotes4all.net" 12 | "randtxt:displays word in random places on screen" 13 | "rfc:randomly displays RFC contents" 14 | "rssfeed:displays rss feed information" 15 | "starwars:runs the asciimation Star Wars movie" 16 | "sysmon:displays a graphical system monitor" 17 | "urlfetcher:displays url contents with typing animation" 18 | ) 19 | 20 | _arguments \ 21 | '(--verbose)--verbose[displays python exception errors (for debugging)]' \ 22 | '(--help)--help[displays this help message]' \ 23 | '*:: :->subcmds' && return 0 24 | 25 | if (( CURRENT == 1 )); then 26 | _describe -t commands "termsaver commands" _1st_arguments && return 0 27 | fi 28 | 29 | case "$words[1]" in 30 | clock) 31 | _arguments \ 32 | '(-m --ampm)--ampm[Shows the clock in am/pm 12-hour format, without seconds]' && return 0 ;; 33 | matrix) 34 | _arguments \ 35 | '(-g --granularity)--granularity[An integer value to define how dirt should the screen be]' \ 36 | '(-d --delay)--delay[Defines the speed (in seconds) of the character movement]' \ 37 | '(-k --kana-only)--kana-only[Displays only Japanese characters (excludes alpha numeric)]' \ 38 | '(-z --zenkaku)--zenkaku[Displays full-width (fattish) Japanese characters]' && return 0 ;; 39 | programmer) 40 | _arguments \ 41 | '(-p --path)--path[Sets the location to search for text-based source files]' \ 42 | '(-d --delay)--delay[Sets the speed of the displaying characters]' && return 0 ;; 43 | randtxt) 44 | _arguments \ 45 | '(-w --word)--word[Sets the word to be displayed]' \ 46 | '(-d --delay)--delay[Sets how long the word will be displayed before randomized again]' && return 0 ;; 47 | rssfeed) 48 | _arguments \ 49 | '(-u --url)--url[The URL path of the RSS feed (text) to be displayed]' \ 50 | '(-r --raw)--rawShows all text available (with HTML if any)' \ 51 | '(-f --format)--formatThe printing format according to values available in RSS feed' && return 0 ;; 52 | sysmon) 53 | _arguments \ 54 | '(-d --delay)--delay[Sets the speed of the displaying characters]' \ 55 | '(-n --no-adjust)--no-adjust[Forces the charts to displays 0 ~ 100% values]' \ 56 | '(-p --path)--path[Sets the location of a file to be monitored]' && return 0 ;; 57 | urlfetcher) 58 | _arguments \ 59 | '(-u --url)--url[Defines the URL location from where the information should be fetched, then displayed]' \ 60 | '(-d --delay)--delay[Sets the speed of the displaying characters]' && return 0 ;; 61 | *) ;; 62 | esac 63 | } 64 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/plugins/exampleplugin/screen/eps.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: ExamplePluginScreen.py 4 | # 5 | # Purpose: An attempt at the starwars asciimation 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2020 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This module contains an example plugin screen. 29 | 30 | The screen class available here is: 31 | 32 | * `ExamplePluginScreen` 33 | """ 34 | 35 | import io 36 | import itertools 37 | import time 38 | 39 | from termsaver.termsaverlib import common 40 | from termsaver.termsaverlib.i18n import _, set_app 41 | from termsaver.termsaverlib.plugins.exampleplugin.screen.base import \ 42 | ExamplePluginScreenBase 43 | # 44 | # Internal modules 45 | # 46 | from termsaver.termsaverlib.screen.base import ScreenBase 47 | from termsaver.termsaverlib.screen.helper.position import PositionHelperBase 48 | 49 | set_app("termsaver-exampleplugin") 50 | 51 | class ExamplePluginScreen(ExamplePluginScreenBase): 52 | """ 53 | An Example Plugin Screen 54 | """ 55 | 56 | def __init__(self, parser = None): 57 | """ 58 | The constructor of this class. 59 | """ 60 | ScreenBase.__init__(self, 61 | "exampleplugin", 62 | _("the example plugin"), 63 | parser 64 | ) 65 | self.cleanup_per_cycle = True 66 | 67 | def _run_cycle(self): 68 | """ 69 | Executes a cycle of this screen. 70 | """ 71 | 72 | print(self.example_echo("Hello World")) 73 | time.sleep(1) 74 | 75 | def _parse_args(self, launchScreenImmediately=True): 76 | """ 77 | Handles the special command-line arguments available for this screen. 78 | Although this is a base screen, having these options prepared here 79 | can save coding for screens that will not change the default options. 80 | 81 | Additionally, this is dependent on the values exposed in `cli_opts`, 82 | passed to this class during its instantiation. Only values properly 83 | configured there will be accepted here. 84 | """ 85 | 86 | # This will parse out all known and unknown arguments. 87 | # See the documentation on the argparse library. 88 | args, unknown_args = self.parser.parse_known_args() 89 | 90 | if launchScreenImmediately: 91 | self.autorun() 92 | else: 93 | return self 94 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/plugins/exampleplugin/constants.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: constants.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver-Example plugin, and should not be 8 | # used or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | Holds constant values used throughout termsaver-exampleplugin plugin. 29 | """ 30 | 31 | # 32 | # Termsaver modules 33 | # 34 | from termsaver.termsaverlib.constants import PropertyClass 35 | 36 | 37 | class Plugin(PropertyClass): 38 | """ 39 | Holds application related properties used by termsaver-exampleplugin plugin 40 | screens. Refer to each of the available properties for detailed 41 | documentation. 42 | """ 43 | 44 | VERSION = "0.1" 45 | """ 46 | Defines the version of termsaver-exampleplugin plugin. This is accessed during 47 | install process, and to any help and usage messages informed by it. 48 | 49 | Refer to CHANGELOG file for a complete history about this project. 50 | """ 51 | 52 | NAME = 'termsaver-exampleplugin' 53 | """ 54 | Defines the termsaver-exampleplugin plugin, usually the plugin package name. 55 | """ 56 | 57 | TITLE = 'TermSaver Example Plugin' 58 | """ 59 | Defines the termsaver-exampleplugin plugin's official name as it should appear 60 | in documentation. 61 | """ 62 | 63 | DESCRIPTION = 'A set of screens for showing an example termsaver plugin.' 64 | """ 65 | Defines the main description of the termsaver-exampleplugin plugin. 66 | """ 67 | 68 | URL = 'http://www.termsaver.info/plugins' 69 | """ 70 | Defines the termsaver-exampleplugin plugin official website address. 71 | """ 72 | 73 | SOURCE_URL = 'http://github.com/brunobraga/termsaver' 74 | """ 75 | Defines the termsaver-exampleplugin plugin official source-code control site, 76 | hosted on GitHub. 77 | """ 78 | 79 | AUTHORS = ['Bruno Braga '] 80 | """ 81 | Defines a list of all authors contributing to the termsaver-exampleplugin plugin. 82 | """ 83 | 84 | 85 | class Settings(PropertyClass): 86 | """ 87 | Holds configuration settings used by termsaver-exampleplugin plugin. Refer to each 88 | of the available properties for detailed documentation. 89 | 90 | Follow the formatting: 91 | 92 | SETTING_NAME = VALUE 93 | \"\"\" 94 | document it! 95 | \"\"\" 96 | 97 | """ 98 | pass 99 | -------------------------------------------------------------------------------- /extras/update_l10n.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################### 3 | # 4 | # file: update_l10n.sh 5 | # 6 | # Purpose: Rebuild localization po files. 7 | # 8 | # Note: This file is part of Termsaver application, and should not be used 9 | # or executed separately. 10 | # 11 | ############################################################################### 12 | # 13 | # Copyright 2012 Termsaver 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 16 | # not use this file except in compliance with the License. You may obtain 17 | # a copy of the License at 18 | # 19 | # http://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 23 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 24 | # License for the specific language governing permissions and limitations 25 | # under the License. 26 | # 27 | ############################################################################### 28 | 29 | ## ############################ 30 | ## CONFIGURABLE SETTINGS: BEGIN 31 | ## ############################ 32 | 33 | # 34 | # Defines the list of languages to be processed by this script, to 35 | # (re)create and (re)compile the i18n (PO/MO) files located in 36 | # 37 | langs="en ja pt" 38 | 39 | # 40 | # Defines the location of the i18n (PO/MO) files, 41 | # within the root path of this project 42 | # 43 | locale_path=locale 44 | 45 | ## ############################ 46 | ## CONFIGURABLE SETTINGS: END 47 | ## ############################ 48 | 49 | # 50 | # Exit on bash errors 51 | # 52 | set -o errexit 53 | 54 | base_path="`pwd`/`dirname $0`/.." 55 | cur_dir=`pwd` 56 | locale_path="$base_path/$locale_path" 57 | 58 | # 59 | # Simple function to read properties from python, 60 | # in this case, the termsaverlib.constants.App properties. 61 | # 62 | function get_prop() { 63 | python -c "from termsaver.termsaverlib import constants as c; print c.App.$@" 64 | } 65 | 66 | cd $base_path 67 | 68 | # remove build stuff (affects the seach here) 69 | sudo rm -rfv build 70 | 71 | for lang in $langs; do 72 | 73 | # create dir, if applicable 74 | d=$locale_path/$lang/LC_MESSAGES 75 | echo "Processing Language [$lang] ..." 76 | mkdir -p $d 77 | 78 | # create file if does not exist yet 79 | omit_header="--omit-header" 80 | new=0 81 | if [ ! -f $d/`get_prop "NAME"`.po ]; then 82 | touch $d/`get_prop "NAME"`.po 83 | omit_header= 84 | new=1 85 | fi 86 | 87 | # process i18n 88 | echo "(Re)building PO file..." 89 | xgettext --language=Python \ 90 | --no-wrap \ 91 | --force-po \ 92 | --join-existing \ 93 | --keyword=_ \ 94 | --force-po \ 95 | $omit_header \ 96 | --package-name="`get_prop "TITLE"`" \ 97 | --package-version=`get_prop "VERSION"` \ 98 | --output=$d/`get_prop "NAME"`.po \ 99 | `find $base_path -iname "*.py" -or -iname "termsaver"` 100 | 101 | # for new files, replace the charset (to avoid warnings) 102 | if [ $new -eq 1 ]; then 103 | sed -i 's/charset=CHARSET/charset=utf-8/' $d/`get_prop "NAME"`.po 104 | fi 105 | 106 | # compile po 107 | echo "(Re)compiling MO file..." 108 | msgfmt $d/`get_prop "NAME"`.po -o $d/`get_prop "NAME"`.mo 109 | 110 | done 111 | 112 | # Done! 113 | echo "Done" 114 | -------------------------------------------------------------------------------- /extras/ubuntu_package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ############################################################################### 3 | # 4 | # file: ubuntu_package.sh 5 | # 6 | # Purpose: Prepares and builds DEB packages. 7 | # 8 | # Note: This file is part of Termsaver application, and should not be used 9 | # or executed separately. 10 | # 11 | ############################################################################### 12 | # 13 | # Copyright 2012 Termsaver 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 16 | # not use this file except in compliance with the License. You may obtain 17 | # a copy of the License at 18 | # 19 | # http://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 23 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 24 | # License for the specific language governing permissions and limitations 25 | # under the License. 26 | # 27 | ############################################################################### 28 | 29 | # 30 | # Important: dput settings must be defined as termsaver 31 | # 32 | 33 | base_path="`pwd`/`dirname $0`/.." 34 | cur_dir=`pwd` 35 | 36 | 37 | # saucy quantal precise oneiric natty maverick lucid karmic jaunty hardy 38 | # invalid (dead) releases: raring intrepid 39 | if [ ! "$1" == "" ]; then 40 | ubuntu_release=$1 41 | else 42 | ubuntu_release=saucy 43 | fi 44 | 45 | ubuntu_suffix=ubuntu1 46 | 47 | 48 | function get_prop() { 49 | python -c "from termsaver.termsaverlib import constants; print constants.App.$@" 50 | } 51 | 52 | 53 | package_name=`get_prop "NAME"` 54 | original_package_version=`get_prop "VERSION"` 55 | 56 | # Fix version specifically for this ubuntu release 57 | sed -i -s "s/VERSION = \"${original_package_version}\"/VERSION = \"${original_package_version}${ubuntu_release}\"/" termsaverlib/constants.py 58 | 59 | package_version=`get_prop "VERSION"` 60 | 61 | # Fix changelog for Ubuntu release (make sure DEBFULLNAME and DEBEMAIL are set) 62 | dch -v ${package_version}-1$ubuntu_suffix -b -D $ubuntu_release -u low -M "Packaging for $ubuntu_release release." 63 | 64 | temp_dir=/tmp/packaging/ 65 | package_dir_name=${package_name}_${package_version} 66 | 67 | echo "Removing old garbage..." 68 | rm -rfv $temp_dir 69 | echo "Done" 70 | 71 | echo "Creating temporary directory..." 72 | mkdir -p $temp_dir 73 | echo "Done" 74 | 75 | echo "Copying project..." 76 | cp -rfv $base_path $temp_dir/$package_dir_name 77 | echo "Done" 78 | 79 | cd $temp_dir/$package_dir_name 80 | 81 | echo "Cleaning up..." 82 | rm -rfv .git* 83 | echo "Done" 84 | 85 | echo "Making original tarball" 86 | mv debian ../ 87 | tar -czvf ../$package_dir_name.orig.tar.gz ../$package_dir_name 88 | mv ../debian . 89 | echo "Done" 90 | 91 | # 92 | # Fix stuff for Ubuntu 93 | # 94 | 95 | # remove quilt 96 | rm -rfv debian/source/format 97 | echo "Done" 98 | 99 | echo "Building package..." 100 | #dpkg-buildpackage -rfakeroot 101 | debuild -S # can not upload deb to launchpad, only sources 102 | echo "Done" 103 | 104 | cd $cur_dir 105 | 106 | # Done! 107 | echo "Finished packaging $package_dir_name" 108 | 109 | # upload to Launchpad PPA 110 | echo "Type anything to upload to LaunchPad... (will receive a confirmation by email)" 111 | read -n 1 112 | dput -f termsaver /tmp/packaging/${package_dir_name}-1${ubuntu_suffix}_source.changes 113 | 114 | # revert changes 115 | git checkout termsaverlib/constants.py 116 | git checkout debian/changelog 117 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/urlfetcher.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: urlfetcher.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | Simple screensaver that displays data from a URL. 29 | 30 | See additional information in the class itself. 31 | 32 | The screen class available here is: 33 | 34 | * `UrlFetcherScreen` 35 | """ 36 | 37 | from termsaver.termsaverlib import constants 38 | from termsaver.termsaverlib.i18n import _ 39 | # 40 | # Internal modules 41 | # 42 | from termsaver.termsaverlib.screen.base.urlfetcher import SimpleUrlFetcherBase 43 | 44 | 45 | class UrlFetcherScreen(SimpleUrlFetcherBase): 46 | """ 47 | Simple screensaver that displays data from a URL. 48 | """ 49 | 50 | def __init__(self, parser = None): 51 | """ 52 | Creates a new instance of this class. 53 | """ 54 | 55 | SimpleUrlFetcherBase.__init__(self, 56 | "urlfetcher", 57 | _("displays url contents with typing animation"), 58 | parser, 59 | '' 60 | ) 61 | 62 | if self.parser: 63 | self.parser.add_argument("-u", "--url", 64 | help="Defines the URL location from where the information should be fetched, then displayed.", 65 | required=True 66 | ) 67 | self.parser.add_argument("-d","--delay", 68 | help="Sets the speed of the displaying characters default is 0.003 of a second (advised to keep)", 69 | default=0.0003 70 | ) 71 | 72 | def _parse_args(self, launchScreenImmediately=True): 73 | args, unknown = self.parser.parse_known_args() 74 | 75 | if args.delay: 76 | self.sleep_between_items = args.delay 77 | 78 | if args.url: 79 | self.url = args.url 80 | self.url = self.url.replace('https://', 'http://') # Fetched URL returns 405 on https. Investigate later. 81 | 82 | if launchScreenImmediately: 83 | self.autorun() 84 | else: 85 | return self 86 | 87 | def _message_no_url(self): 88 | """ 89 | """ 90 | return _(""" 91 | You just need to provide the URL from where %(app_title)s will read and 92 | display on screen. 93 | 94 | If you do not have any idea which URL to use, check out some examples here: 95 | 96 | RFC 97 | RFC-1034 - http://tools.ietf.org/rfc/rfc1034.txt 98 | 99 | See a RFC list from Wikipedia: 100 | http://en.wikipedia.org/wiki/List_of_RFCs 101 | (remember to use the txt version) 102 | 103 | """) % { 104 | 'app_title': constants.App.TITLE, 105 | } 106 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/constants.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: constants.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | Holds constant values used throughout termsaver application. 29 | """ 30 | 31 | 32 | class PropertyClass: 33 | """ 34 | A base class that defines a class as a holder for properties only, not to 35 | be instantiated in any circumstances. 36 | """ 37 | 38 | def __init__(self): 39 | """ 40 | This class (and sub-classes) should not be instantiated. 41 | """ 42 | raise NotImplementedError("This class cannot be instantiated!") 43 | 44 | 45 | class App(PropertyClass): 46 | """ 47 | Holds application related properties used by termsaver screens. 48 | Refer to each of the available properties for detailed documentation. 49 | """ 50 | 51 | VERSION = "0.6" 52 | """ 53 | Defines the version of termsaver application. This is accessed during 54 | install process, and to any help and usage messages informed by it. 55 | 56 | Refer to CHANGELOG file for a complete history about this project. 57 | """ 58 | 59 | NAME = 'termsaver' 60 | """ 61 | Defines the termsaver application, as it is executed from command-line. 62 | """ 63 | 64 | TITLE = 'TermSaver' 65 | """ 66 | Defines the termsaver application's official name as it should appear 67 | in documentation. 68 | """ 69 | 70 | DESCRIPTION = 'A simple text-based terminal screensaver' 71 | """ 72 | Defines the main description of the termsaver application. 73 | """ 74 | 75 | URL = 'http://github.com/brunobraga/termsaver' 76 | """ 77 | Defines the termsaver official website address. 78 | """ 79 | 80 | SOURCE_URL = 'http://github.com/brunobraga/termsaver' 81 | """ 82 | Defines the termsaver official source-code control site, hosted on GitHub. 83 | """ 84 | 85 | AUTHORS = [ 86 | 'Bruno Braga ', 87 | 'Shelby Jueden ', 88 | 'Alexander Riccio ', 89 | 'Eddie Dover ', 90 | ] 91 | """ 92 | Defines a list of all authors contributing to the termsaver application. 93 | """ 94 | 95 | 96 | class Settings(PropertyClass): 97 | """ 98 | Holds configuration settings used by termsaver application. Refer to each 99 | of the available properties for detailed documentation. 100 | """ 101 | 102 | CHAR_DELAY_SECONDS = 0.003 103 | """ 104 | Defines basically the speed in which the text will be displayed, character 105 | by character, giving a cool impression of an automated type writing machine 106 | Default value is 0.003 seconds (3 milliseconds). It is advised to use 107 | values between 0.01 and 0.001. 108 | """ 109 | 110 | FETCH_INTERVAL_SECONDS = 3600 111 | """ 112 | Defines the interval between each fetching of data over the Internet. 113 | Default value is 1 hour. 114 | """ 115 | -------------------------------------------------------------------------------- /doc/termsaver.1: -------------------------------------------------------------------------------- 1 | .TH "TERMSAVER" "1" "22 March 2012" "Termsaver" "" 2 | .SH "NAME" 3 | Termsaver \- A simple text-based terminal screensaver 4 | .SH "SYNTAX" 5 | .B termsaver 6 | .RI [ SCREEN ] 7 | .RI [ OPTIONS ] 8 | .br 9 | .SH "DESCRIPTION" 10 | .B Termsaver 11 | is a simple alternative for simulating command-line based 12 | screensavers right on the terminal, in text-based format. 13 | .P 14 | To start the screensaver, execute 15 | .B Termsaver 16 | command with proper options as described in detail below, and to close it, 17 | just use the standard 18 | .I Ctrl+C 19 | to interrupt it (or close the terminal window if you are on a desktop 20 | environment and no longer need it). 21 | .br 22 | .SH "SCREEN" 23 | The 24 | .B Termsaver 25 | application, to work properly, requires a 26 | .I screen 27 | as argument, which represents the name of the screensaver to be loaded. Each 28 | .I screen, 29 | in turn, will have its own set of optional arguments, documented in its 30 | .B help 31 | option. 32 | . 33 | .P 34 | Here follows a list of currently available screens (note that this information 35 | might become outdated if updates are not fully documented here, so always rely 36 | on the 37 | .B help 38 | option to display all 39 | .I screens 40 | available): 41 | .TP 42 | .B quotes4all 43 | displays recent quotes from quotes4all.net 44 | .TP 45 | .B asciiartfarts 46 | displays ascii images from asciiartfarts.com (NSFW) 47 | .TP 48 | .B img2ascii 49 | display images as ascii characters 50 | .TP 51 | .B rssfeed 52 | displays rss feed information 53 | .TP 54 | .B clock 55 | displays a digital clock on screen 56 | .TP 57 | .B randtxt 58 | displays word in random places on screen 59 | .TP 60 | .B rfc 61 | randomly displays RFC contents 62 | .TP 63 | .B programmer 64 | displays source code in typing animation (optional pygments support) 65 | .TP 66 | .B urlfetcher 67 | displays url contents with typing animation 68 | .TP 69 | .B jokes4all 70 | displays recent jokes from jokes4all.net (NSFW) 71 | .TP 72 | .B matrix 73 | displays a matrix movie alike screensaver 74 | .TP 75 | .B sysmon 76 | displays a graphic of CPU/MEM usage over time 77 | .TP 78 | .B starwars 79 | displays the star wars asciimation from http://asciimation.co.nz/ 80 | .P 81 | Refer to 82 | .B help 83 | option for additional information for each 84 | .I screen 85 | usage and example. 86 | .br 87 | .SH "OPTIONS" 88 | This program follow the usual GNU command line syntax, with long 89 | options starting with two dashes (`\-'). 90 | A summary of options is included below. 91 | .TP 92 | .B \-h, \-\-help 93 | Displays this help message 94 | .TP 95 | .B \-v, \-\-verbose 96 | Displays python exception errors (for debugging) 97 | .P 98 | .SH "EXAMPLES" 99 | .TP 100 | Check all available screens to use: 101 | .B termsaver --help 102 | .br 103 | .TP 104 | Run random text screensaver with extra arguments: 105 | .B termsaver 106 | .I randtxt 107 | .BR --word " HelloWorld " --delay " 1 " 108 | 109 | .SH "SEE ALSO" 110 | See more information about this project at: 111 | .br 112 | .I http://termsaver.brunobraga.net 113 | 114 | .br 115 | .SH "COPYRIGHT" 116 | Licensed under the Apache License, Version 2.0 (the "License"); you may 117 | not use this file except in compliance with the License. You may obtain 118 | a copy of the License at 119 | .P 120 | http://www.apache.org/licenses/LICENSE-2.0 121 | .P 122 | Unless required by applicable law or agreed to in writing, software 123 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 124 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 125 | License for the specific language governing permissions and limitations 126 | under the License. 127 | .br 128 | .SH "AUTHORS" 129 | Termsaver was written by Bruno Braga 130 | .RI < bruno@brunobraga.net >, 131 | .br 132 | and contributors. 133 | .PP 134 | .SH "BUGS" 135 | Report bugs to authors at: 136 | .br 137 | .I http://github.com/brunobraga/termsaver 138 | 139 | 140 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/wttr.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: wttr.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | Simple screensaver that displays data from wttr.in. 29 | """ 30 | 31 | import sys 32 | import time 33 | 34 | # 35 | # Internal modules 36 | # 37 | from termsaver.termsaverlib import constants 38 | from termsaver.termsaverlib.i18n import _ 39 | from termsaver.termsaverlib.screen.base import ScreenBase 40 | from termsaver.termsaverlib.screen.base.urlfetcher import SimpleUrlFetcherBase 41 | from termsaver.termsaverlib.screen.helper.position import PositionHelperBase 42 | 43 | 44 | class WTTRScreen(SimpleUrlFetcherBase, PositionHelperBase): 45 | 46 | units = None 47 | typing = False 48 | narrow = False 49 | 50 | def __init__(self, parser = None): 51 | 52 | SimpleUrlFetcherBase.__init__(self, 53 | "wttr", 54 | _("displays a weather report from wttr.in"), 55 | parser, 56 | 'https://wttr.in/?a' 57 | ) 58 | 59 | # # set defaults for this screen 60 | # self.cleanup_per_cycle = True 61 | # self.cleanup_per_item = False 62 | self.sleep_between_items = 20 63 | # self.delay = 0.015 64 | 65 | if self.parser: 66 | self.parser.add_argument("-d", "--delay", help="Delay in seconds between weather refresh. Lower this when using --typing mode.", type=int, default=300) # 5 minutes 67 | # self.parser.add_argument("-l", "--location", help="Location to fetch weather for", type=str, default="") 68 | self.parser.add_argument("-t", "--typing", help="Types the weather report out instead of printing it", action="store_true", default=False) 69 | self.parser.add_argument("-u", "--units", help="Units to use for temperature and wind speed.", type=str, default=None, choices=["metric", "imperial"]) 70 | self.parser.add_argument("-n", "--narrow", help="Narrow the output to 80 characters", action="store_true", default=False) 71 | 72 | def _run_cycle(self): 73 | 74 | self.clear_screen() 75 | 76 | additions = "" 77 | if self.units is not None: 78 | additions += "m" if self.units == "metric" else "u" 79 | if self.narrow: 80 | additions += "n" 81 | if additions != "": 82 | self.url += additions 83 | new_text = self.fetch(self.url, 'GET', 'curl/7.37.0',).decode("utf-8") 84 | self.get_terminal_size() 85 | new_text = self.center_text_vertically(new_text) 86 | # This breaks the layout it but I'm not exactly sure why. 87 | #new_text = self.center_text_horizontally(new_text) 88 | if self.typing_print: 89 | self.typing_print(new_text) 90 | else: 91 | print(new_text) 92 | time.sleep(self.sleep_between_items) 93 | 94 | def _parse_args(self, launchScreenImmediately=True): 95 | args, unknown = self.parser.parse_known_args() 96 | self.sleep_between_items = args.delay 97 | self.typing = args.typing 98 | self.units = args.units 99 | self.narrow = args.narrow 100 | # self.location = args.location 101 | if launchScreenImmediately: 102 | self.autorun() 103 | else: 104 | return self -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/asciiartfarts.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: asciiartfarts.py 4 | # 5 | # Purpose: refer to python doc for documentation details. 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This module contains a simple screen that connects to asciiartfarts.com RSS 29 | feeds to display ascii arts on screen. 30 | See additional information in the class itself. 31 | 32 | The screen class available here is: 33 | 34 | * `AsciiArtFartsScreen` 35 | """ 36 | 37 | import time 38 | 39 | from termsaver.termsaverlib.i18n import _ 40 | # 41 | # Internal modules 42 | # 43 | from termsaver.termsaverlib.screen.base.urlfetcher import SimpleUrlFetcherBase 44 | from termsaver.termsaverlib.screen.helper.position import PositionHelperBase 45 | 46 | 47 | class AsciiArtFartsScreen(SimpleUrlFetcherBase, PositionHelperBase): 48 | """ 49 | A simple screen that connects to asciiartfarts.com RSS feeds to display 50 | ascii arts on screen. 51 | 52 | From its base classes, the functionality provided here bases on the 53 | settings defined below: 54 | 55 | * sleep between items: 5 seconds 56 | not so much time between images 57 | 58 | * clean up each cycle: True 59 | this will force the screen to be cleaned (cleared) before each new 60 | cycle is displayed 61 | 62 | * center in vertical 63 | 64 | * center in horizontal 65 | 66 | * clean dirt: HTML
 tags
 67 | 
 68 |         * clean up each item: True
 69 |           this will force the screen to be cleaned (cleared) before each image
 70 |           is displayed
 71 |     """
 72 | 
 73 |     def __init__(self, parser = None):
 74 |         """
 75 |         The constructor of this class, using most default values from its super
 76 |         class, `SimpleRSSFeedScreenBase`.
 77 | 
 78 |         The display of the ascii arts here are basically based on getting the
 79 |         description tag of the RSS feed, that constains a dirty HTML ascii art.
 80 | 
 81 |         NOTE: Maybe NSFW (Not Safe For Work)
 82 |         """
 83 |         SimpleUrlFetcherBase.__init__(self,
 84 |             "asciiartfarts",
 85 |             _("displays ascii images from asciiartfarts.com (NSFW)"),
 86 |             parser,
 87 |             'http://www.asciiartfarts.com/random.cgi',
 88 |         )
 89 | 
 90 |         if self.parser:
 91 |           self.parser.add_argument("-d", "--delay", help="Delay in seconds between images", type=int, default=5)
 92 | 
 93 |     def _run_cycle(self):
 94 |         """
 95 |         Executes a cycle of this screen. Overriden from its superclass because
 96 |         it needs to must randomize the URL to be fetched in every screen cycle.
 97 |         """
 98 |         self.clear_screen()
 99 |         new_text = self.process_data(self.fetch(self.url)).decode("utf-8")
100 |         self.get_terminal_size()
101 |         new_text = self.center_text_vertically(new_text)
102 |         new_text = self.center_text_horizontally(new_text)
103 |         self.typing_print(new_text)
104 |         time.sleep(self.sleep_between_items)
105 | 
106 |     def _parse_args(self, launchScreenImmediately=True):
107 |       args, unknown = self.parser.parse_known_args()
108 |       self.sleep_between_items = args.delay
109 |       if launchScreenImmediately:
110 |         self.autorun()
111 |       else:
112 |         return self
113 | 
114 |     def process_data(self, data):
115 |       data_string = data.decode('utf-8')
116 |       data_string = data_string.split('
')[2].split('
')[0] 117 | return data_string.encode('utf-8') -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/helper/typing.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: typing.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | A helper class used for screens that require more dynamic output to users. 29 | See additional information in the class itself. 30 | 31 | The helper class available here is: 32 | 33 | * `TypingHelperBase` 34 | 35 | """ 36 | # 37 | # Python built-in modules 38 | # 39 | import sys 40 | import time 41 | 42 | from termsaver.termsaverlib import constants 43 | # 44 | # Internal modules 45 | # 46 | from termsaver.termsaverlib.screen.helper import ScreenHelperBase 47 | 48 | 49 | class TypingHelperBase(ScreenHelperBase): 50 | """ 51 | This helper class gives functionality to screens to print out information 52 | in a more interactive way, simulating a typing writer machine, based on 53 | two main speed control properties: 54 | 55 | * `delay`: defines the delay for printing out characters of a string 56 | 57 | * `line_delay`: defines the delay for printing out new lines within a 58 | string (sometimes, setting different proportions make a lot of a 59 | difference) 60 | 61 | If no values are defined by the screen itself, default values should be 62 | used. The `delay` is set in `constants.Settings.CHAR_DELAY_SECONDS`, and 63 | the `line_delay` is 10 times the value of delay. 64 | 65 | To use this screen helper is pretty straightforward, just call the method: 66 | 67 | * `typing_print`: this will print the specified text string using the 68 | speed controls `delay` and `line_delay`. 69 | 70 | """ 71 | 72 | delay = None 73 | """ 74 | Defines the character printing delay, to give a cool visual of a 75 | typing machine. This value is measured in seconds, and default marks are 76 | defined in `constants.Settings.CHAR_DELAY_SECONDS`. 77 | """ 78 | 79 | line_delay = None 80 | """ 81 | Defines the delay imposed to every new line prior to char printing. By 82 | default, its value is 10x the `delay`. 83 | """ 84 | 85 | def typing_print(self, text): 86 | """ 87 | Prints text with standard output to allow side-by-side printing, and 88 | give the impression of a typing writer machine. The speed is controlled 89 | by properties of this class: `delay` and `line_delay`. 90 | 91 | Arguments: 92 | 93 | * text: the text to be printed in typing style 94 | 95 | Notes: 96 | 97 | * This also supports new lines (\n) 98 | * blank spaces, due to its lack of meaning, are ignored for speed 99 | limiting, so they will be flushed all at once. 100 | 101 | """ 102 | # set defaults 103 | if self.delay is None: 104 | self.delay = constants.Settings.CHAR_DELAY_SECONDS 105 | 106 | if self.line_delay is None: 107 | self.line_delay = 10 * self.delay 108 | splitText = text.split("\n") 109 | for line in splitText: 110 | for char in line: 111 | sys.stdout.write(char) 112 | 113 | # only pause if it is not a blank space 114 | if char != ' ': 115 | time.sleep(self.delay) 116 | 117 | sys.stdout.flush() 118 | 119 | # need to re-print the line removed from the split 120 | sys.stdout.write('\n') 121 | 122 | time.sleep(self.line_delay) # specific pause for new lines 123 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/__init__.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: __init__.py 4 | # 5 | # Purpose: refer to python doc for documentation details. 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This module itself holds simple functions to better handle the screens 29 | available within this package. Available functions: 30 | 31 | * `get_available_screens`: Gets the available screens in this package for 32 | dynamic instantiation. 33 | 34 | * `build_screen_usage_list`: Builds a simple string with a list of all 35 | available screens, to be used in usage() methods. 36 | 37 | The modules available in this package are: 38 | 39 | * `asciiartfarts`: displays ascii images from asciiartfarts.com 40 | 41 | * `clock`: displays a digital clock 42 | 43 | * `sysmon`: displays a graphic for CPU/Mem usage 44 | 45 | * `jokes4all`: displays recent jokes from jokes4all.net 46 | 47 | * `programmer`: displays source code in typing animation 48 | 49 | * `quotes4all`: displays recent quotes from quotes4all.net 50 | 51 | * `randtxt`: displays word in random places on screen 52 | 53 | * `rfc`: randomly displays RFC contents 54 | 55 | * `rssfeed`: displays rss feed information 56 | 57 | * `urlfetcher`: displays url contents with typing animation 58 | 59 | * `matrix`: displays a matrix movie alike screensaver 60 | 61 | This also contains the following sub-packages: 62 | 63 | * `base`: holds base classes that are used by all screens within termsaver 64 | application 65 | 66 | * `helper`: holds all helper classes used by termsaver screens, to add 67 | reusable functionality to them 68 | """ 69 | 70 | import inspect 71 | # 72 | # Python built-in modules 73 | # 74 | import os 75 | import sys 76 | 77 | from termsaver.termsaverlib.plugins import get_available_plugin_screens 78 | # 79 | # Internal modules 80 | # 81 | from termsaver.termsaverlib.screen import base 82 | 83 | 84 | def get_available_screens(): 85 | """ 86 | Gets the available screens in this package for dynamic instantiation. 87 | """ 88 | ignore_list = ['__init__.py'] 89 | screens = [] 90 | 91 | # for module in absoluteFilePaths(os.path.join(os.path.dirname(__file__))): 92 | sys.path.insert(1, os.path.join(os.path.dirname(__file__))) 93 | 94 | for module in os.listdir(os.path.join(os.path.dirname(__file__))): 95 | if module in ignore_list or module[-3:] != '.py': 96 | continue 97 | 98 | module_name = module[:-3] 99 | m = __import__(module_name, globals(), locals()) 100 | 101 | # loop module's classes in search for the ones inheriting Screenbase 102 | # and ignore name (no need) with underscore variable 103 | for name, obj in inspect.getmembers(m): 104 | if inspect.isclass(obj) and issubclass(obj, base.ScreenBase) \ 105 | and not name.endswith("Base"): 106 | screens.append(obj) 107 | 108 | # find plugins 109 | screens.extend(get_available_plugin_screens()) 110 | 111 | return screens 112 | 113 | def build_screen_usage_list(): 114 | """ 115 | Builds a simple string with a list of all available screens, 116 | to be used in usage() methods. 117 | """ 118 | screens = get_available_screens() 119 | screen_space = max([len(s().name) for s in screens]) 120 | 121 | return '\n '.join([''.join([s().name, ' ', 122 | ' ' * (screen_space - len(s().name) + 1), 123 | s().description]) for s in get_available_screens()]) 124 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/helper/imageconverter.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: imageconverter.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | 28 | from PIL import Image 29 | import os 30 | import io 31 | import requests 32 | 33 | class ImageConverter: 34 | source_path = False 35 | options = False 36 | 37 | def is_link(self): 38 | if 'http' == self.source_path[0:4].lower(): 39 | return True 40 | return False 41 | 42 | def image_type(self): 43 | extension = self.source_path[-4:].lower() 44 | imgtype = extension.strip('.') 45 | 46 | return imgtype 47 | 48 | def get_image(self): 49 | if self.is_link(): 50 | r = requests.get(self.source_path, stream=True) 51 | image = Image.open(io.BytesIO(r.content)) 52 | else: 53 | image = Image.open(self.source_path) 54 | 55 | return image 56 | 57 | def process_image(self, twidth, theight, scale = 1): 58 | 59 | image = self.get_image() 60 | image_type = self.image_type() 61 | 62 | width = image.size[0] 63 | height = image.size[1] 64 | 65 | twidth -= 1 66 | theight -= 1 67 | 68 | ri = width / height 69 | rs = twidth / theight 70 | 71 | if rs > ri: 72 | width = width * theight / height 73 | height = theight 74 | else: 75 | width = twidth 76 | height = height * twidth / width 77 | 78 | width = int(width) 79 | height = int(height) 80 | 81 | return image.resize((width * scale, height * scale), Image.LANCZOS) 82 | 83 | def convert_image(self, source_path, height, width, options): 84 | self.source_path = source_path 85 | self.options = options 86 | 87 | if 'scale' in self.options: 88 | scale = self.options['scale'] 89 | else: 90 | scale = 1 91 | 92 | image = self.process_image(height, width, scale) 93 | specter = ' .:;+=xX$&' 94 | 95 | if 'wide' in self.options: 96 | wide = self.options['wide'] 97 | else: 98 | wide = 2 99 | 100 | if 'contrast' in self.options: 101 | specter = ' ░▒▓█' 102 | 103 | if 'customcharset' in self.options: 104 | specter = self.options['customcharset'] 105 | 106 | if 'invert' in self.options: 107 | specter = specter[::-1] 108 | 109 | # per img/frame 110 | image = image.convert('RGB') 111 | string = '' 112 | width,height = image.size 113 | last_row = 0 114 | contrast_levels = [] 115 | contrast_gap = 255 / len(specter) 116 | for gap in range(len(specter)): 117 | contrast_levels.append(contrast_gap * gap) 118 | 119 | for y in range(height): 120 | for x in range(width): 121 | if y != last_row: 122 | string += '\n' 123 | last_row += 1 124 | try: 125 | r, g, b = image.getpixel((x,y)) 126 | except: 127 | r, g, b, a = image.getpixel((x,y)) 128 | pixel_value = (r * 0.3 + g * 0.59 + b * 0.11) 129 | levels = [] 130 | for level in contrast_levels: 131 | levels.append(abs(pixel_value - level)) 132 | character = specter[levels.index(min(levels))] * wide 133 | string += character 134 | 135 | return string -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/rssfeed.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: rssfeed.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | Simple screensaver that displays data from a RSS feed. 29 | 30 | See additional information in the class itself. 31 | 32 | The screen class available here is: 33 | 34 | * `RSSFeedScreen` 35 | """ 36 | 37 | import sys 38 | 39 | from termsaver.termsaverlib import constants 40 | from termsaver.termsaverlib.i18n import _ 41 | from termsaver.termsaverlib.screen.base import ScreenBase 42 | # 43 | # Internal modules 44 | # 45 | from termsaver.termsaverlib.screen.base.rssfeed import RSSFeedScreenBase 46 | 47 | 48 | class RSSFeedScreen(ScreenBase, RSSFeedScreenBase): 49 | """ 50 | Simple screensaver that displays data from a RSS feed. 51 | 52 | RSS Feed Screen configuration: 53 | 54 | * sleep between items: 3 seconds 55 | 56 | * clean up each cycle: True 57 | this will force the screen to be cleaned (cleared) before each joke 58 | is displayed 59 | 60 | * character display delay: 0.015 61 | a bit faster than traditional speeds, because users are not 62 | interested in the char print animation as much. 63 | 64 | * clean up each item: False 65 | 66 | * display format: 67 | 68 | '%(title)s (%(pubDate)s)\n%(description)s\n%(link)s\n.\n' 69 | """ 70 | 71 | def __init__(self, parser = None): 72 | """ 73 | Creates a new instance of this class. 74 | """ 75 | 76 | ScreenBase.__init__(self, 77 | "rssfeed", 78 | _("displays rss feed information"), 79 | parser 80 | ) 81 | 82 | RSSFeedScreenBase.__init__(self, 83 | parser, 84 | None, 85 | ["pubDate", "title", "link", "description"], 86 | '%(title)s (%(pubDate)s)\n%(description)s\n%(link)s\n.\n', 87 | ) 88 | 89 | # set defaults for this screen 90 | self.cleanup_per_cycle = True 91 | self.cleanup_per_item = False 92 | self.sleep_between_items = 3 93 | self.delay = 0.015 94 | 95 | if self.parser: 96 | self.parser.add_argument("-u", "--url", help=_("URL of the RSS feed to be used."), required=True) 97 | 98 | def _message_no_url(self): 99 | """ 100 | Defines a method to be overriden by inheriting classes, with the 101 | purpose to display extra help information for specific errors. 102 | """ 103 | return _(""" 104 | You just need to provide the URL of the RSS feed from where %(app_title)s will 105 | read and display on screen. 106 | 107 | If you do not have any idea which RSS to use, check out some examples here: 108 | 109 | CNN 110 | Top Stories - http://rss.cnn.com/rss/edition.rss 111 | World - http://rss.cnn.com/rss/edition_world.rss 112 | Technology - http://rss.cnn.com/rss/edition_technology.rss 113 | 114 | See CNN's complete list of RSS syndication here: 115 | http://edition.cnn.com/services/rss/ 116 | 117 | Lifehacker - http://www.lifehacker.com/index.xml 118 | Note: Lifehacker uses HTML to deliver "description" contents in the RSS, 119 | so you might need to change the format to something like: 120 | --format "%%(title)s (%%(pubDate)s)\\n" 121 | """) % { 122 | 'app_title': constants.App.TITLE, 123 | } 124 | 125 | def _parse_args(self, launchScreenImmediately=True): 126 | return RSSFeedScreenBase._parse_args(self, launchScreenImmediately) 127 | 128 | def _run_cycle(self): 129 | RSSFeedScreenBase._run_cycle(self) -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/rfc.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: rfc.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | A simple screen that fetches documents from RFC (Request for Comments). 29 | 30 | The screen class available here is: 31 | 32 | * `RFCScreen` 33 | """ 34 | 35 | # 36 | # Python built-in modules 37 | # 38 | import random 39 | 40 | from termsaver.termsaverlib.i18n import _ 41 | from termsaver.termsaverlib.screen.base import ScreenBase 42 | # 43 | # Internal modules 44 | # 45 | from termsaver.termsaverlib.screen.base.urlfetcher import SimpleUrlFetcherBase 46 | 47 | 48 | class RFCScreen(SimpleUrlFetcherBase): 49 | """ 50 | A simple screen that fetches documents from RFC (Request for Comments). 51 | 52 | Request for Comments (RFC) is a memorandum published by the Internet 53 | Engineering Task Force (IETF) describing methods, behaviors, research, or 54 | innovations applicable to the working of the Internet and Internet- 55 | connected systems. 56 | 57 | More information about RFC at Wikipedia: 58 | http://en.wikipedia.org/wiki/Request_for_Comments 59 | 60 | This screen basically does the same as its super class, 61 | `SimpleUrlFetcherBase`, with a simple difference that it must randomize 62 | the URL to be fetched in every screen cycle. This is done by overriding 63 | the `run` command. 64 | 65 | The list of valid RFCs, according to Wikipedia, are listed in `valid_rfc`. 66 | Although this may vary in time, small out-of-date information will still 67 | not affect the main purpose of this screen. 68 | """ 69 | 70 | valid_rfc = [ 71 | 768, 791, 792, 793, 826, 854, 855, 862, 863, 864, 868, 903, 72 | 1034, 1035, 1036, 1058, 1059, 1087, 1112, 1119, 1149, 1157, 1176, 1294, 73 | 1305, 1321, 1350, 1436, 1441, 1459, 1730, 1777, 1855, 1889, 1918, 1939, 74 | 1945, 1948, 1950, 1951, 1952, 1964, 1991, 2080, 2119, 2131, 2177, 2195, 75 | 2228, 2246, 2251, 2252, 2253, 2254, 2255, 2256, 2326, 2327, 2328, 2351, 76 | 2362, 2397, 2407, 2408, 2409, 2440, 2445, 2453, 2460, 2549, 2570, 2606, 77 | 2616, 2740, 2743, 2744, 2810, 2811, 2812, 2813, 2821, 2822, 2853, 2865, 78 | 2866, 2965, 2974, 3022, 3031, 3056, 3080, 3162, 3261, 3284, 3286, 3315, 79 | 3339, 3376, 3401, 3402, 3403, 3404, 3405, 3501, 3530, 3720, 3783, 3801, 80 | 3977, 4213, 4217, 4271, 4287, 4251, 4291, 4353, 4408, 4422, 4541, 4575, 81 | 4579, 4634, 4646, 4787, 4960, 5023, 5533, 5969, 6455, 937, 951, 959, 82 | ] 83 | """ 84 | Extracted from Wikipedia: http://en.wikipedia.org/wiki/List_of_RFCs 85 | on 2012-02-28, 02:11 AM 86 | """ 87 | 88 | url_format = "http://tools.ietf.org/rfc/rfc%d.txt" 89 | """ 90 | The URL format that can return a text version of a specific RFC number. 91 | """ 92 | 93 | def __init__(self, parser = None): 94 | """ 95 | The constructor of this class, using most default values from its super 96 | class, `SimpleUrlFetcherBase`. 97 | """ 98 | SimpleUrlFetcherBase.__init__(self, 99 | "rfc", 100 | _("randomly displays RFC contents"), 101 | parser, 102 | "localhost", 103 | ) # base class require a URL 104 | 105 | def _run_cycle(self): 106 | """ 107 | Executes a cycle of this screen. Overriden from its superclass because 108 | it needs to must randomize the URL to be fetched in every screen cycle. 109 | """ 110 | # Randomize next URL to fetch from one of the valid list 111 | self.url = self.url_format % self.valid_rfc[ 112 | random.randint(0, len(self.valid_rfc) - 1)] 113 | 114 | data = self.fetch(self.url) 115 | self.clear_screen() 116 | self.typing_print(data.decode("utf-8")) 117 | 118 | def _parse_args(self, launchScreenImmediately=True): 119 | if launchScreenImmediately: 120 | self.autorun() 121 | else: 122 | return self 123 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: __init__.py 4 | # 5 | # Purpose: refer to python doc for documentation details. 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This module itself holds simple functions to better handle the screens 29 | available within any plugins installed. Available functions: 30 | 31 | * `get_available_plugin_screens`: Gets the available screens in 32 | sub-directories {plugin}/screen/ for dynamic instantiation. 33 | 34 | The modules available in this package are installed on-demand, so they are 35 | not documented here. 36 | 37 | How to create plugins 38 | ===================== 39 | 40 | The main script termsaver will execute a dynamic search for all screens 41 | that inherit from the `ScreenBase` class. For plugins, however, screens are 42 | not placed in the same directory of the built-in screens, but instead into 43 | their own location. 44 | 45 | The directory structure of a plugin should be like: 46 | 47 | plugins/ 48 | | 49 | |---- __init__.py 50 | | 51 | |---- my_plugin/ 52 | | | 53 | | |---- __init__.py 54 | | | 55 | | |---- screen 56 | | | | 57 | | | |---- __init__.py 58 | | | | 59 | | | |---- my_screen.py 60 | | | | 61 | | | |---- ... 62 | | | | 63 | 64 | Additional rules before you begin: 65 | 66 | (1) Naming Conventions 67 | The application name must be in the format: termsaver-{plugin-name}, and 68 | the directory to be created inside the plugins will be {plugin-name}. 69 | 70 | Python does not like dashes for module names, so be careful with names you 71 | pick. 72 | 73 | (2) Screens 74 | Each screen you design (inside the plugins/{plugin-name}/screen directory) 75 | must inherit from the `ScreenBase` class, as this is the base for the 76 | application to find the screen, and handle input/output accordingly. 77 | 78 | 79 | This structure is designed to immitate termsaver's main structure, so once you 80 | get familiar with it, it should be piece of cake to manage your own "space". 81 | 82 | """ 83 | 84 | import inspect 85 | # 86 | # Python built-in modules 87 | # 88 | import os 89 | import sys 90 | 91 | # 92 | # Internal modules 93 | # 94 | from termsaver.termsaverlib.screen import base 95 | 96 | 97 | def get_available_plugin_screens(): 98 | """ 99 | Gets the available screens in this package for dynamic instantiation. 100 | """ 101 | ignore_list = ['__init__.py'] 102 | screens = [] 103 | for plugin in os.listdir(os.path.join(os.path.dirname(__file__))): 104 | 105 | if ("__pycache__" in plugin): continue 106 | 107 | if (os.path.isdir(os.path.join(os.path.dirname(__file__), plugin))): 108 | # we are inside the plugin directory, get screens available in 109 | # screens directory 110 | 111 | for module in os.listdir(os.path.join(os.path.dirname(__file__), 112 | plugin, "screen")): 113 | 114 | if module in ignore_list or module[-3:] != '.py': 115 | continue 116 | 117 | module_name = plugin + ".screen." + module[:-3] 118 | 119 | if os.path.join(os.path.dirname(__file__)) not in sys.path: 120 | sys.path.append(os.path.join(os.path.dirname(__file__))) 121 | 122 | m = __import__(module_name, globals(), locals(), 123 | [module_name.rsplit(".", 1)[-1]]) 124 | 125 | # loop module's classes in search for the ones inheriting 126 | # Screenbase and ignore name (no need) with underscore variable 127 | for name, obj in inspect.getmembers(m): 128 | if inspect.isclass(obj) and issubclass(obj, 129 | base.ScreenBase) and not name.endswith("Base"): 130 | screens.append(obj) 131 | return screens 132 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/programmer.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: programmer.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | A screen to read source code files (or any other) in a typing writer animation 29 | See additional information in the class itself. 30 | 31 | The helper class available here is: 32 | 33 | * `ProgrammerScreen` 34 | """ 35 | import os 36 | from argparse import ArgumentParser 37 | 38 | from termsaver.termsaverlib import constants, exception 39 | from termsaver.termsaverlib.i18n import _ 40 | from termsaver.termsaverlib.screen.base.filereader import FileReaderBase 41 | 42 | 43 | class ProgrammerScreen(FileReaderBase): 44 | """ 45 | A simple screen that will display any text (hei programmer, source code!), 46 | on screen in a typing writer animation. 47 | 48 | From options available in `FileReaderBase`, this will use: 49 | 50 | * `FileReaderBase.cleanup_per_cycle` as True 51 | 52 | * `FileReaderBase.cleanup_per_file` as True 53 | """ 54 | 55 | def __init__(self, parser = None): 56 | """ 57 | Creates a new instance of this class (used by termsaver script) 58 | 59 | From its base classes, the functionality provided here bases on the 60 | settings defined below: 61 | 62 | * clean up each cycle: True 63 | this will force the screen to be cleaned (cleared) before 64 | each new cycle is displayed 65 | 66 | * clean up each file: True 67 | this will force the screen to be cleaned (cleared) before 68 | each new file is displayed 69 | """ 70 | FileReaderBase.__init__(self, 71 | "programmer", 72 | _("displays source code in typing animation (with pygments support)"), 73 | parser 74 | ) 75 | 76 | self.cleanup_per_cycle = True 77 | self.cleanup_per_file = True 78 | self.colorize = True 79 | self.ignore_binary = True 80 | 81 | def _parse_args(self, launchScreenImmediately=True): 82 | """ 83 | Handles the special command-line arguments available for this screen. 84 | Although this is a base screen, having these options prepared here 85 | can save coding for screens that will not change the default options. 86 | 87 | Additionally, this is dependent on the values exposed in `cli_opts`, 88 | passed to this class during its instantiation. Only values properly 89 | configured there will be accepted here. 90 | """ 91 | args, unknown = self.parser.parse_known_args() 92 | 93 | if args.path: 94 | # make sure argument is a valid value (existing path) 95 | self.path = args.path.strip() 96 | if not os.path.exists(self.path) and self.path[0:4].lower() != 'http': 97 | raise exception.PathNotFoundException(path=args.path) 98 | 99 | if args.delay: 100 | self.delay = args.delay 101 | else: 102 | self.delay = constants.Settings.CHAR_DELAY_SECONDS 103 | 104 | if launchScreenImmediately: 105 | self.autorun() 106 | else: 107 | return self 108 | 109 | def _message_no_path(self): 110 | """ 111 | The specific helper message in case there is no path informed in the 112 | command-line arguments. 113 | """ 114 | return _(""" 115 | You just need to provide the path to the location from where %(app_title)s will 116 | read and display on screen. 117 | 118 | If you do not have any code in your local machine, just get some interesting 119 | project from the Internet, such as Django (http://www.djangoproject.com): 120 | 121 | If you have access to git, you may download it at: 122 | git clone https://github.com/django/django.git 123 | 124 | Or, just download the zipped source and unpack it on your local machine: 125 | https://www.djangoproject.com/download/ 126 | """) % { 127 | 'app_title': constants.App.TITLE, 128 | } 129 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/jokes4all.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: jokes4all.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | Simple screensaver that displays recent jokes from http://jokes4all.net 29 | website, from its hourly updated RSS feed. 30 | 31 | See additional information in the class itself. 32 | 33 | The screen class available here is: 34 | 35 | * `Jokes4AllScreen` 36 | """ 37 | 38 | import time 39 | 40 | from termsaver.termsaverlib.i18n import _ 41 | from termsaver.termsaverlib.screen.base import ScreenBase 42 | # 43 | # Internal modules 44 | # 45 | from termsaver.termsaverlib.screen.base.urlfetcher import SimpleUrlFetcherBase 46 | from termsaver.termsaverlib.screen.helper.position import PositionHelperBase 47 | 48 | 49 | class Jokes4AllRSSFeedScreen(SimpleUrlFetcherBase, PositionHelperBase): 50 | """ 51 | Simple screensaver that displays recent jokes from http://jokes4all.net 52 | website, from its hourly updated RSS feed. 53 | 54 | RSS Feed Screen configuration: 55 | 56 | * sleep between items: 30 seconds 57 | this is to allow people enough time for them to read the joke 58 | 59 | * clean up each cycle: True 60 | this will force the screen to be cleaned (cleared) before each joke 61 | is displayed 62 | 63 | * character display delay: 0.015 64 | a bit faster than traditional speeds, because users are not 65 | interested in the char print animation as much. 66 | 67 | * clean up each item: True 68 | this will force the screen to be cleaned (cleared) before each image 69 | is displayed 70 | 71 | * display format: 72 | 73 | '\n%(description)s\n\n%(pubDate)s %(link)s\n' 74 | 75 | * center in vertical 76 | """ 77 | 78 | def __init__(self, parser = None): 79 | """ 80 | The constructor of this class, using most default values from its super 81 | class, `SimpleRSSFeedScreenBase`. 82 | 83 | NOTE: Maybe NSFW (Not Safe For Work) 84 | """ 85 | SimpleUrlFetcherBase.__init__(self, 86 | 'jokes4all', 87 | _("displays random jokes from jokes4all.net (NSFW)"), 88 | parser, 89 | 'https://jokes4all.net' 90 | ) 91 | 92 | 93 | # set defaults for this screen 94 | self.sleep_between_items = 30 95 | self.line_delay = 0 96 | self.cleanup_per_item = True 97 | self.cleanup_per_cycle = True 98 | self.center_vertically = True 99 | 100 | if self.parser: 101 | self.parser.add_argument("-d", "--delay", help="Delay in seconds between jokes", type=int, default=self.sleep_between_items) 102 | 103 | def _parse_args(self, launchScreenImmediately=True): 104 | args, unknown = self.parser.parse_known_args() 105 | 106 | if args.delay: 107 | self.sleep_between_items = args.delay 108 | 109 | if launchScreenImmediately: 110 | self.autorun() 111 | else: 112 | return self 113 | 114 | def _run_cycle(self): 115 | """ 116 | Executes a cycle of this screen. Overriden from its superclass because 117 | it needs to must randomize the URL to be fetched in every screen cycle. 118 | """ 119 | self.clear_screen() 120 | new_text = self.process_data(self.fetch(self.url)).decode("utf-8") 121 | self.get_terminal_size() 122 | new_text = self.center_text_vertically(new_text) 123 | new_text = self.center_text_horizontally(new_text) 124 | self.typing_print(new_text) 125 | time.sleep(self.sleep_between_items) 126 | 127 | def process_data(self, data): 128 | data_string = data.decode('utf-8') 129 | # Get the text between the first
and the next
130 | data_string = data_string.split('
')[1].split('
')[0] 131 | if (data_string): 132 | data_string = data_string.replace("
", "\n") 133 | # data_string = data_string.split('
')[2].split('
')[0] 134 | return data_string.encode('utf-8') -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/quotes4all.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: quotes4all.py 4 | # 5 | # Purpose: holds base classes used by screens in termsaver 6 | # refer to module documentation for details 7 | # 8 | # Note: This file is part of Termsaver application, and should not be used 9 | # or executed separately. 10 | # 11 | ############################################################################### 12 | # 13 | # Copyright 2012 Termsaver 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 16 | # not use this file except in compliance with the License. You may obtain 17 | # a copy of the License at 18 | # 19 | # http://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 23 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 24 | # License for the specific language governing permissions and limitations 25 | # under the License. 26 | # 27 | ############################################################################### 28 | """ 29 | Simple screensaver that displays recent jokes from http://jokes4all.net 30 | website, from its hourly updated RSS feed. 31 | 32 | See additional information in the class itself. 33 | 34 | The screen class available here is: 35 | 36 | * `Quotes4AllScreen` 37 | """ 38 | 39 | import time 40 | 41 | from termsaver.termsaverlib.i18n import _ 42 | # 43 | # Internal modules 44 | # 45 | from termsaver.termsaverlib.screen.base.urlfetcher import SimpleUrlFetcherBase 46 | from termsaver.termsaverlib.screen.helper.position import PositionHelperBase 47 | 48 | 49 | class Quotes4AllScreen(SimpleUrlFetcherBase, PositionHelperBase): 50 | """ 51 | Simple screensaver that displays recent jokes from http://jokes4all.net 52 | website, from its hourly updated RSS feed. 53 | 54 | RSS Feed Screen configuration: 55 | 56 | * sleep between items: 10 seconds 57 | this is to allow people enough time for them to read the quote 58 | 59 | * clean up each cycle: True 60 | this will force the screen to be cleaned (cleared) before each joke 61 | is displayed 62 | 63 | * character display delay: 0.015 64 | a bit faster than traditional speeds, because users are not 65 | interested in the char print animation as much. 66 | 67 | * clean up each item: True 68 | this will force the screen to be cleaned (cleared) before each image 69 | is displayed 70 | 71 | * display format: 72 | 73 | '\n"%(description)s" -- %(title)s\n' 74 | 75 | * center in vertical 76 | 77 | * center in horizontal 78 | 79 | * clean dirt: new lines 80 | 81 | """ 82 | 83 | def __init__(self, parser = None): 84 | """ 85 | Creates a new instance of this class (used by termsaver script) 86 | """ 87 | SimpleUrlFetcherBase.__init__(self, 88 | 'quotes4all', 89 | _("displays random quotes from quotes4all.net (NSFW)"), 90 | parser, 91 | 'https://quotes4all.net' 92 | ) 93 | 94 | if self.parser: 95 | self.parser.add_argument("-d", "--delay", help="Delay in seconds between images", type=int, default=10) 96 | 97 | # set defaults for this screen 98 | self.sleep_between_items = 10 99 | self.line_delay = 0 100 | self.cleanup_per_cycle = True 101 | self.cleanup_per_item = True 102 | self.center_vertically = True 103 | self.center_horizontally = True 104 | self.clean_dirt = ["\n", " "] 105 | 106 | 107 | def _parse_args(self, launchScreenImmediately=True): 108 | args, unknown = self.parser.parse_known_args() 109 | if args.delay: 110 | self.sleep_between_items = args.delay 111 | 112 | if launchScreenImmediately: 113 | self.autorun() 114 | else: 115 | return self 116 | 117 | 118 | def _run_cycle(self): 119 | """ 120 | Executes a cycle of this screen. Overriden from its superclass because 121 | it needs to must randomize the URL to be fetched in every screen cycle. 122 | """ 123 | new_text = self.process_data(self.fetch(self.url)).decode("utf-8") 124 | self.get_terminal_size() 125 | new_text = self.center_text_vertically(new_text) 126 | new_text = self.center_text_horizontally(new_text) 127 | self.clear_screen() 128 | self.typing_print(new_text) 129 | time.sleep(self.sleep_between_items) 130 | 131 | def process_data(self, data): 132 | data_string = data.decode('utf-8') 133 | # Get the text between the first
and the next
134 | data_string = data_string.split('
')[1].split('
')[0] 135 | if (data_string): 136 | data_string = data_string.replace("
", "\n") 137 | # data_string = data_string.split('
')[2].split('
')[0] 138 | return data_string.encode('utf-8') -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/starwars.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: starwars.py 4 | # 5 | # Purpose: An attempt at the starwars asciimation 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2020 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This module contains a simple screen that loads the sw1.txt file used by 29 | the star wars asciimation. 30 | 31 | The screen class available here is: 32 | 33 | * `StarWarsScreen` 34 | """ 35 | 36 | import io 37 | import itertools 38 | import time 39 | from pathlib import Path 40 | 41 | from termsaver.termsaverlib import common 42 | from termsaver.termsaverlib.i18n import _ 43 | # 44 | # Internal modules 45 | # 46 | from termsaver.termsaverlib.screen.base import ScreenBase 47 | from termsaver.termsaverlib.screen.helper.position import PositionHelperBase 48 | 49 | 50 | class StarWarsScreen(ScreenBase, PositionHelperBase): 51 | """ 52 | Screen that displays the star wars text from the 53 | star wars asciimation. 54 | (http://www.asciimation.co.nz/). 55 | 56 | From its base classes, the functionality provided here bases on the 57 | settings defined below: 58 | 59 | * clean up each cycle: True 60 | this will force the screen to be cleaned (cleared) before each new 61 | cycle is displayed 62 | """ 63 | 64 | def __init__(self, parser = None): 65 | """ 66 | The constructor of this class. 67 | """ 68 | ScreenBase.__init__(self, 69 | "starwars", 70 | _("displays the star wars asciimation on screen"), 71 | parser 72 | ) 73 | self.cleanup_per_cycle = True 74 | self.is_initalized = False 75 | 76 | def reshape(self,lst, n): 77 | return [lst[i*n:(i+1)*n] for i in range(len(lst)//n)] 78 | 79 | def _run_cycle(self): 80 | """ 81 | Executes a cycle of this screen. 82 | """ 83 | 84 | if self.is_initalized is False: 85 | filepath = Path(__file__).resolve().parent.parent.parent / "data" / "sw1.txt" 86 | with io.open(filepath,"rb") as swfile: 87 | lines = swfile.readlines() 88 | lines = [line.decode('utf-8') for line in lines] 89 | 90 | self.current_frame = 0 91 | self.star_wars = self.reshape(lines,14) 92 | self.time_per_frame = 15 93 | self.is_initalized = True 94 | 95 | frame_time = float(self.star_wars[self.current_frame][0]) / self.time_per_frame 96 | print("\r\n" + "".join(self.star_wars[self.current_frame][1:14])) 97 | time.sleep(frame_time) 98 | self.current_frame += 1 99 | 100 | def _usage_options_example(self): 101 | """ 102 | Describe here the options and examples of this screen. 103 | 104 | The method `_parse_args` will be handling the parsing of the options 105 | documented here. 106 | 107 | Additionally, this is dependent on the values exposed in `cli_opts`, 108 | passed to this class during its instantiation. Only values properly 109 | configured there will be accepted here. 110 | """ 111 | print (_(""" 112 | 113 | The Star Wars Asciimation is copyright Simon Jansen (jansens@asciimation.co.nz) 114 | and viewable standalone on the web at http://asciimation.co.nz. 115 | 116 | Options: 117 | -h, --help Displays this help message 118 | 119 | """)) 120 | 121 | def _parse_args(self, launchScreenImmediately=True): 122 | """ 123 | Handles the special command-line arguments available for this screen. 124 | Although this is a base screen, having these options prepared here 125 | can save coding for screens that will not change the default options. 126 | 127 | See `_usage_options_example` method for documentation on each of the 128 | options being parsed here. 129 | 130 | Additionally, this is dependent on the values exposed in `cli_opts`, 131 | passed to this class during its instantiation. Only values properly 132 | configured there will be accepted here. 133 | """ 134 | 135 | if launchScreenImmediately: 136 | self.autorun() 137 | else: 138 | return self 139 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/base/urlfetcher.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: urlfetcher.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This module contains a screen base class that handles URL fetched contents. 29 | See additional information in the class itself. 30 | 31 | The helper classes available here are: 32 | 33 | * `UrlFetcherBase` 34 | * `SimpleUrlFetcherBase` 35 | """ 36 | 37 | from termsaver.termsaverlib import constants, exception 38 | from termsaver.termsaverlib.i18n import _ 39 | # 40 | # Internal modules 41 | # 42 | from termsaver.termsaverlib.screen.base import ScreenBase 43 | from termsaver.termsaverlib.screen.helper.typing import TypingHelperBase 44 | from termsaver.termsaverlib.screen.helper.urlfetcher import \ 45 | URLFetcherHelperBase 46 | 47 | 48 | class UrlFetcherBase(TypingHelperBase, 49 | URLFetcherHelperBase): 50 | """ 51 | A base class used to handle URL fetched contents, and display them 52 | accordingly. This also includes the `TypingHelperBase` to add functionality 53 | of typing writer display. 54 | 55 | The instantiation of this class takes two additional arguments, compared 56 | with its base class: 57 | 58 | * url: the URL address to fetch data from 59 | 60 | * `delay`: defines the delay for printing out characters of 61 | a string 62 | """ 63 | 64 | url = "" 65 | """ 66 | the URL address to fetch data from 67 | """ 68 | def __init__(self, parser, url=None, delay=None): 69 | """ 70 | Creates a new instance of this class. 71 | 72 | This constructor has two additional arguments, compared with its base 73 | class: 74 | 75 | * url: the URL address to fetch data from 76 | 77 | * `delay`: defines the delay for printing out characters of 78 | a string 79 | """ 80 | if self.parser: 81 | self.parser.add_argument("-d","--delay", action="store", type=int, help="""Sets the speed of the displaying characters 82 | default is%(default_delay)s of a second""" % {'default_delay': constants.Settings.CHAR_DELAY_SECONDS}) 83 | 84 | self.delay = delay 85 | self.url = url 86 | self.parser = parser 87 | 88 | def _run_cycle(self): 89 | """ 90 | Executes a cycle of this screen. 91 | 92 | The actions taken here, for each cycle, are as follows: 93 | 94 | * retrieve data from `url` 95 | * print using `typing_print` 96 | """ 97 | data = self.fetch(self.url) 98 | self.clear_screen() 99 | self.typing_print(data.decode("utf-8")) 100 | 101 | def _message_no_url(self): 102 | """ 103 | Defines a method to be overriden by inheriting classes, with the 104 | purpose to display extra help information for specific errors. 105 | """ 106 | return "" 107 | 108 | def _parse_args(self, launchScreenImmediately=True): 109 | """ 110 | Handles the special command-line arguments available for this screen. 111 | Although this is a base screen, having these options prepared here 112 | can save coding for screens that will not change the default options. 113 | 114 | See `_usage_options_example` method for documentation on each of the 115 | options being parsed here. 116 | 117 | Additionally, this is dependent on the values exposed in `cli_opts`, 118 | passed to this class during its instantiation. Only values properly 119 | configured there will be accepted here. 120 | """ 121 | args,unknown = self.parser.parse_known_args() 122 | if args.delay: 123 | try: 124 | self.delay = float(args.delay) 125 | except: 126 | raise exception.InvalidOptionException("delay") 127 | 128 | if args.url: 129 | try: 130 | self.url = self.fix_uri(args.url) 131 | except Exception as e: 132 | error_message = "" 133 | if hasattr(e, 'message'): 134 | error_message = e.message 135 | else: 136 | error_message = e 137 | raise exception.InvalidOptionException("url", error_message) 138 | 139 | # last validations 140 | if self.url in (None, ''): 141 | raise exception.InvalidOptionException("url", 142 | _("It is mandatory option"), help=self._message_no_url()) 143 | 144 | if launchScreenImmediately: 145 | self.autorun() 146 | else: 147 | return self 148 | 149 | 150 | class SimpleUrlFetcherBase(ScreenBase, UrlFetcherBase): 151 | """ 152 | Inherits the `UrlFetcherBase` class to handle basic URL fetching. 153 | This will simplify the use of UrlFetcherBase by forcing a fixed 154 | URL, and simplify the code of screens inheriting from it. 155 | """ 156 | 157 | def __init__(self, name, description, parser, url, delay=None): 158 | """ 159 | Creates a new instance of this class. 160 | 161 | This constructor has forced the url argument, compared with its base 162 | class, as it has no command line options to define its value manually 163 | """ 164 | ScreenBase.__init__(self, name, description, parser) 165 | UrlFetcherBase.__init__(self, parser, url, delay) 166 | 167 | 168 | def _run_cycle(self): 169 | UrlFetcherBase._run_cycle(self) 170 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/exception.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: exceptions.py 4 | # 5 | # Purpose: holds termsaver special exceptions 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This module holds special exceptions triggered by termsaver (and handled 29 | internally as well, but with more human-readable treatment). 30 | 31 | The classes available here are: 32 | 33 | * `TermSaverException` 34 | A generic exception that implements read-only functionality for its 35 | inheriting classes. 36 | 37 | * `ScreenNotFoundException` 38 | An exception that happens when termsaver is dealing with non existing 39 | screens. 40 | 41 | * `PathNotFoundException` 42 | An exception that happens when termsaver is dealing with non existing 43 | files. 44 | 45 | * `UrlException` 46 | An exception that happens when termsaver is dealing with URL connectvitiy 47 | issues. 48 | 49 | """ 50 | 51 | 52 | class TermSaverException(Exception): 53 | """ 54 | A base exception class providing additional read-only feature to its 55 | inheriting classes. You must fill the `readonly` list to enable a property 56 | as read-only. 57 | """ 58 | 59 | readonly = [] 60 | """ 61 | Defines a list to place names of properties that should be read-only. 62 | """ 63 | 64 | help_msg = '' 65 | """ 66 | An extra string of information to help guide users on exception issues. 67 | """ 68 | 69 | def __init__(self, *args, **kwargs): 70 | """ 71 | Instantiate a new exception object. 72 | 73 | You may use the extra property `help` when instantiating this. 74 | """ 75 | 76 | Exception.__init__(self, *args) 77 | 78 | # get the help argument dynamically from kwargs, if applicable 79 | if "help" in kwargs: 80 | self.help_msg = kwargs['help'] 81 | 82 | # mark this property as read-only 83 | self.readonly.append("help") 84 | 85 | def __setattr__(self, name, val): 86 | """ 87 | Override of original to check for read-only properties, throwing 88 | exception if tempered with. 89 | """ 90 | if name not in self.readonly: 91 | self.__dict__[name] = val 92 | else: 93 | raise Exception("%s.%s is read only!" % (self.__class__.__name__, 94 | name)) 95 | 96 | 97 | class PathNotFoundException(TermSaverException): 98 | """ 99 | Exception to handle special cases when a path required to run could not be 100 | found in the file system. 101 | """ 102 | 103 | path = '' 104 | """ 105 | The name of the screen that could not be found by termsaver. 106 | """ 107 | 108 | def __init__(self, path, *args, **kwargs): 109 | """ 110 | Instantiates this exception class, with an additional parameter for the 111 | name of the screen not found by termsaver. This value is accessible by 112 | """ 113 | TermSaverException.__init__(self, *args, **kwargs) 114 | if 'path' not in self.readonly: 115 | self.path = path 116 | 117 | # mark this property as read-only 118 | self.readonly.append('path') 119 | 120 | 121 | class UrlException(TermSaverException): 122 | """ 123 | Exception to handle special cases when connectivity to a specific URL was 124 | not successful. 125 | """ 126 | 127 | url = '' 128 | """ 129 | The name of the screen that could not be found by termsaver. 130 | """ 131 | 132 | def __init__(self, url, *args, **kwargs): 133 | """ 134 | Instantiates this exception class, with an additional parameter for the 135 | name of the screen not found by termsaver. This value is accessible by 136 | """ 137 | TermSaverException.__init__(self, *args, **kwargs) 138 | if 'url' not in self.readonly: 139 | self.url = url 140 | 141 | # mark this property as read-only 142 | self.readonly.append('url') 143 | 144 | 145 | class InvalidOptionException(TermSaverException): 146 | """ 147 | Exception to handle special cases when user uses comman line options 148 | wrongfully. 149 | """ 150 | 151 | option_name = '' 152 | """ 153 | The name of the screen that could not be found by termsaver. 154 | """ 155 | 156 | def __init__(self, option_name, *args, **kwargs): 157 | """ 158 | Instantiates this exception class, with an additional parameter for the 159 | name of the screen not found by termsaver. This value is accessible by 160 | """ 161 | TermSaverException.__init__(self, *args, **kwargs) 162 | if 'option_name' not in self.readonly: 163 | self.option_name = option_name 164 | 165 | # mark this property as read-only 166 | self.readonly.append('option_name') 167 | 168 | 169 | class XmlException(TermSaverException): 170 | """ 171 | Exception to handle XML issues. 172 | """ 173 | 174 | name = '' 175 | """ 176 | The name of the file path or URL that had issues with parsing 177 | """ 178 | 179 | def __init__(self, name, *args, **kwargs): 180 | """ 181 | Instantiates this exception class, with an additional parameter for the 182 | name of the screen not found by termsaver. This value is accessible by 183 | """ 184 | TermSaverException.__init__(self, *args, **kwargs) 185 | self.name = name 186 | 187 | # mark this property as read-only 188 | self.readonly.append('name') 189 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/randtxt.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: randtxt.py 4 | # 5 | # Purpose: holds base classes used by screens in termsaver 6 | # refer to module documentation for details 7 | # 8 | # Note: This file is part of Termsaver application, and should not be used 9 | # or executed separately. 10 | # 11 | ############################################################################### 12 | # 13 | # Copyright 2012 Termsaver 14 | # 15 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 16 | # not use this file except in compliance with the License. You may obtain 17 | # a copy of the License at 18 | # 19 | # http://www.apache.org/licenses/LICENSE-2.0 20 | # 21 | # Unless required by applicable law or agreed to in writing, software 22 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 23 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 24 | # License for the specific language governing permissions and limitations 25 | # under the License. 26 | # 27 | ############################################################################### 28 | """ 29 | Simple screensaver that displays a text in random position on screen. 30 | 31 | See additional information in the class itself. 32 | 33 | The screen class available here is: 34 | 35 | * `RandTxtScreen` 36 | """ 37 | 38 | import time 39 | 40 | from termsaver.termsaverlib import constants, exception 41 | from termsaver.termsaverlib.i18n import _ 42 | from termsaver.termsaverlib.screen.base import ScreenBase 43 | from termsaver.termsaverlib.screen.helper.position import PositionHelperBase 44 | from termsaver.termsaverlib.screen.helper.typing import TypingHelperBase 45 | 46 | 47 | class RandTxtScreen(ScreenBase, 48 | TypingHelperBase, 49 | PositionHelperBase): 50 | """ 51 | Simple screensaver that displays a text in random position on screen. 52 | 53 | This screen offers the additional options to customize its behavior: 54 | 55 | * `delay`: Defines the freezing time for a word to be displayed on 56 | screen, before a next randomization (cycle). If never changed by 57 | command-line options, it will assume the value of `FREEZE_WORD_DELAY` 58 | 59 | * `word`: defines the word to be displayed on screen 60 | for files 61 | """ 62 | 63 | word = '' 64 | """ 65 | Holds the word to be displayed on screen 66 | """ 67 | 68 | freeze_delay = 0 69 | """ 70 | Defines the freezing time for a word to be displayed on screen, before a 71 | next randomization (cycle). If never changed by command-line options, 72 | it will assume the value of `FREEZE_WORD_DELAY`. 73 | """ 74 | 75 | FREEZE_WORD_DELAY = 3 76 | """ 77 | A default freezing time for a word to be displayed on screen, before a 78 | next randomization (cycle). Its value is set to 3 seconds. 79 | """ 80 | 81 | def __init__(self, parser = None): 82 | """ 83 | Creates a new instance of this class. 84 | """ 85 | ScreenBase.__init__(self, 86 | "randtxt", 87 | _("displays word in random places on screen"), 88 | parser 89 | ) 90 | if self.parser: 91 | self.parser.add_argument("-w", "--word", type=str, required=False, help="The words to randomly display on screen.") 92 | self.parser.add_argument("-d", "--delay", type=float, required=False, default=self.freeze_delay, help="The delay between changing words.") 93 | self.word = constants.App.TITLE 94 | self.delay = 0.01 95 | self.line_delay = 0 96 | self.cleanup_per_cycle = True 97 | self.freeze_delay = self.FREEZE_WORD_DELAY 98 | 99 | def _run_cycle(self): 100 | """ 101 | Executes a cycle of this screen. 102 | 103 | The actions taken here, for each cycle, are as follows: 104 | 105 | * randomize text position vertically and horizontally 106 | * print using `typing_print` 107 | """ 108 | # calculate random position based on screen size 109 | self.get_terminal_size() 110 | 111 | txt = self.randomize_text_vertically( 112 | self.randomize_text_horizontally(self.word)) 113 | 114 | self.typing_print(txt) 115 | 116 | time.sleep(self.freeze_delay) 117 | 118 | def _usage_options_example(self): 119 | """ 120 | Describe here the options and examples of this screen. 121 | 122 | The method `_parse_args` will be handling the parsing of the options 123 | documented here. 124 | 125 | Additionally, this is dependent on the values exposed in `cli_opts`, 126 | passed to this class during its instantiation. Only values properly 127 | configured there will be accepted here. 128 | """ 129 | print (_(""" 130 | Example: 131 | 132 | $ %(app_name)s %(screen)s 133 | This will trigger the screensaver to display the default word %(app_title)s 134 | in random locations of the screen 135 | 136 | $ %(app_name)s %(screen)s -w FooBar 137 | This will trigger the screensaver to display the default word FooBar 138 | in random locations of the screen 139 | """) % { 140 | 'app_name': constants.App.NAME, 141 | 'app_title': constants.App.TITLE, 142 | 'screen': self.name, 143 | 'default_delay': self.FREEZE_WORD_DELAY, 144 | }) 145 | 146 | def _parse_args(self, launchScreenImmediately=True): 147 | """ 148 | Handles the special command-line arguments available for this screen. 149 | Although this is a base screen, having these options prepared here 150 | can save coding for screens that will not change the default options. 151 | 152 | See `_usage_options_example` method for documentation on each of the 153 | options being parsed here. 154 | 155 | Additionally, this is dependent on the values exposed in `cli_opts`, 156 | passed to this class during its instantiation. Only values properly 157 | configured there will be accepted here. 158 | """ 159 | args,unknown = self.parser.parse_known_args() 160 | if args.delay: 161 | try: 162 | # make sure argument is a valid value (float) 163 | self.freeze_delay = float(args.delay) 164 | except: 165 | raise exception.InvalidOptionException("delay") 166 | if args.word: 167 | if args.word in (None, ''): 168 | raise exception.InvalidOptionException("word") 169 | self.word = args.word 170 | 171 | if launchScreenImmediately: 172 | self.autorun() 173 | else: 174 | return self 175 | -------------------------------------------------------------------------------- /tests/test.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: test.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | 28 | # 29 | # Python built-in modules 30 | # 31 | import os 32 | import sys 33 | import unittest 34 | 35 | # 36 | # Import from parent path 37 | # 38 | sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), 39 | os.path.pardir))) 40 | 41 | # 42 | # Internal Modules (can only call this after the above PATH update) 43 | # 44 | from termsaver.termsaverlib.screen.helper import position 45 | 46 | 47 | class PositionHelperTestCase(unittest.TestCase): 48 | 49 | p = None 50 | 51 | def setUp(self): 52 | self.p = position.PositionHelperBase() 53 | self.p.get_terminal_size() 54 | 55 | def testCenterHorizontallyText(self): 56 | 57 | # check no text 58 | t = "" 59 | self.p.center_text_horizontally(t) 60 | 61 | # test small word(s) 62 | t = "x" 63 | for __ in range(3): 64 | t += t 65 | nt = self.p.center_text_horizontally(t) 66 | self.assertEqual(nt.find(t), 67 | (self.p.geometry['x'] - len(t)) / 2) 68 | 69 | # test long word(s) 70 | t = "x" * 500 71 | for __ in range(3): 72 | t += t 73 | nt = self.p.center_text_horizontally(t) 74 | self.assertEqual(nt.find(t[0]), 0) 75 | 76 | # test multiple lines 77 | t = "\n".join(["x" * 25 for __ in range(10)]) 78 | for __ in range(3): 79 | t += t 80 | nt = self.p.center_text_horizontally(t) 81 | 82 | # test long multiple lines 83 | t = "\n".join(["x" * 500 for __ in range(10)]) 84 | for __ in range(3): 85 | t += t 86 | nt = self.p.center_text_horizontally(t) 87 | 88 | def testHorizontallyRandomizeText(self): 89 | 90 | # check no text 91 | t = "" 92 | self.p.randomize_text_horizontally(t) 93 | 94 | # test small word(s) 95 | t = "x" 96 | for __ in range(3): 97 | t += t 98 | self.p.randomize_text_horizontally(t) 99 | 100 | # test long word(s) 101 | t = "x" * 500 102 | for __ in range(3): 103 | t += t 104 | self.p.randomize_text_horizontally(t) 105 | 106 | # test multiple lines 107 | t = "\n".join(["x" * 25 for __ in range(10)]) 108 | for __ in range(3): 109 | t += t 110 | self.p.randomize_text_horizontally(t) 111 | 112 | # test long multiple lines 113 | t = "\n".join(["x" * 500 for __ in range(10)]) 114 | for __ in range(3): 115 | t += t 116 | self.p.randomize_text_horizontally(t) 117 | 118 | def testCenterVerticallyText(self): 119 | 120 | # check no text 121 | t = "" 122 | self.p.center_text_vertically(t) 123 | 124 | # test small word(s) 125 | t = "x" 126 | for __ in range(5): 127 | t += t 128 | nt = self.p.center_text_vertically(t) 129 | self.assertEqual(len(nt.split('\n')), 130 | (self.p.geometry['y'] - len(t.split('\n'))) / 2 + 1) 131 | self.assertEqual(len(nt.split('\n')) - 1, self.p.position['y']) 132 | 133 | # test long word(s) 134 | t = "x" * 500 135 | for __ in range(3): 136 | t += t 137 | self.p.center_text_vertically(t) 138 | 139 | # test multiple lines 140 | t = "\n".join(["x" * 25 for __ in range(10)]) 141 | for __ in range(3): 142 | t += t 143 | self.p.center_text_vertically(t) 144 | 145 | # test long multiple lines 146 | t = "\n".join(["x" * 500 for __ in range(10)]) 147 | for __ in range(3): 148 | t += t 149 | self.p.center_text_vertically(t) 150 | 151 | #class CommonTestCase(unittest.TestCase): 152 | # 153 | # path = '/tmp/temp-delete-ok' 154 | # file_count = 0 155 | # files_list = [] 156 | # randomness = 10 157 | # 158 | # def setUp(self): 159 | # 160 | # unittest.TestCase.setUp(self) 161 | # 162 | # # 163 | # # Create a recursive random directory tree for testing 164 | # # 165 | # 166 | # # initialize values 167 | # self.file_count = 0 168 | # self.files_list = [] 169 | # 170 | # def create(path, count=1): 171 | # # create dummy files for testing 172 | # for i in range(count, self.randomness): 173 | # name = os.path.join(path, ''.join(random.choice( 174 | # string.ascii_lowercase + string.digits) \ 175 | # for _ in range(5))) 176 | # if not os.path.exists(name): 177 | # if random.random() > 0.5: # 50% probability threshold 178 | # os.makedirs(name) 179 | # create(name, i) 180 | # else: 181 | # name += ".txt" 182 | # f = open(name, "w") 183 | # f.close() 184 | # self.file_count += 1 185 | # self.files_list.append(name) 186 | # 187 | # if not os.path.exists(self.path): 188 | # os.makedirs(self.path) 189 | # else: 190 | # # force cleanup for s clean start 191 | # shutil.rmtree(self.path) 192 | # 193 | # # randomize directories and files 194 | # create(self.path) 195 | # 196 | # def tearDown(self): 197 | # 198 | # unittest.TestCase.tearDown(self) 199 | # 200 | # # clean up 201 | # shutil.rmtree(self.path) 202 | # 203 | # def testRecurseToExec(self): 204 | # 205 | # file_count = [0] # muttable required for sub-function access 206 | # 207 | # def count(): 208 | # file_count[0] += 1 209 | # 210 | # common.recurse_to_exec(self.path, count) 211 | # 212 | # self.assertEqual(file_count[0], self.file_count) 213 | # 214 | # def testRecurseToList(self): 215 | # 216 | # files_list = common.recurse_to_list(self.path) 217 | # 218 | # # sort lists for comparison 219 | # files_list.sort() 220 | # self.files_list.sort() 221 | # 222 | # self.assertListEqual(files_list, self.files_list) 223 | 224 | 225 | if __name__ == '__main__': 226 | unittest.main() 227 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/helper/xmlreader.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: xmlreader.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | A helper class used for screens that require XML handling. See 29 | additional information in the class itself. 30 | 31 | The helper class available here is: 32 | 33 | * `XMLReaderHelperBase` 34 | 35 | """ 36 | 37 | # 38 | # Python built-in modules 39 | # 40 | import os 41 | from xml.dom.minidom import Node, parse, parseString 42 | 43 | from termsaver.termsaverlib import exception 44 | # 45 | # Internal modules 46 | # 47 | from termsaver.termsaverlib.screen.helper import ScreenHelperBase 48 | 49 | 50 | class XMLReaderHelperBase(ScreenHelperBase): 51 | """ 52 | This helper class will handle basic XML parsing, not trying to solve all 53 | mysteries of the universe here. What we are looking for are main nodes that 54 | contain repetitive data, commonly found on a dataset, or RSS feed. More 55 | complex handling is not treated at this point, but it might be implemented 56 | if the need surfaces. 57 | 58 | The basic instantiation of this class require you to inform 2 arguments: 59 | 60 | * `base_node`: Defines the primary node where the data must be 61 | retrieved from. 62 | 63 | * `tags`: Defines which tags within the XML must be parsed to build a 64 | list of dictionaries. 65 | 66 | Those two arguments will give the hint about where is the data and which 67 | piece of it you are looking for. 68 | 69 | For actually getting the data, you will need to: 70 | 71 | * prepare a raw data (file content, Internet data, etc) into a 72 | XML object, named `__doc`; and 73 | * parse the XML object into a more convenient list of dictionaries 74 | that will be populated in `data` property. 75 | 76 | To prepare the data, you have 2 options: 77 | 78 | * `doc_xml_string`: a method that will create a dom xml document from 79 | a text string (obviously it must be a XML) 80 | 81 | * `doc_xml_file`: a method that will create a dom xml document from 82 | a file content (obviously it must be a XML) 83 | 84 | Once you have the XML properly prepared, and stored in `__doc`, you can 85 | call the parsing method: 86 | 87 | * `parse_data`: this will actually execute the action to extract the 88 | information you are looking for based on the arguments passed 89 | in the instantiation. 90 | 91 | """ 92 | 93 | __doc = None 94 | """ 95 | Holds the xml.dom.minidom document object 96 | """ 97 | 98 | clean_dirt = [] 99 | """ 100 | Holds a list of strings that will be cleaned up from each result in the 101 | XML data, when placing them into the `data` property. This can be pretty 102 | handy to remove trailing spaces, new lines, or unwanted HTML tags from the 103 | data. 104 | """ 105 | 106 | base_node = None 107 | """ 108 | Defines the primary node where the data must be retrieved from. 109 | """ 110 | 111 | tags = [] 112 | """ 113 | Defines which tags within the XML must be parsed to build a 114 | list of dictionaries. 115 | """ 116 | 117 | data = None 118 | """ 119 | Holds a list, created from properly parsing the dom document object in 120 | `__doc`, as specified with `base_node` and `tags` filtering. 121 | """ 122 | 123 | def __init__(self, base_node, tags): 124 | """ 125 | Creates a new instance of this class. 126 | 127 | Arguments: 128 | 129 | * `base_node`: Defines the primary node where the data must be 130 | retrieved from. 131 | 132 | * `tags`: Defines which tags within the XML must be parsed to build a 133 | list of dictionaries. 134 | """ 135 | self.base_node = base_node 136 | self.tags = tags 137 | 138 | def parse_data(self): 139 | """ 140 | Only call this once you have already created the dom document object, 141 | by calling either `doc_xml_file` or `doc_xml_string` methods. 142 | 143 | This will parse the document into a list, much simpler to deal with. 144 | On the logic here is done, the list is available in the property `data` 145 | """ 146 | def get_note_value(node, node_type): 147 | result = '' 148 | for node2 in node: 149 | for node3 in node2.childNodes: 150 | if node3.nodeType == node_type: 151 | result += node3.data 152 | # clean possible dirt 153 | for t in self.clean_dirt: 154 | # execute a loop here for dealing with multiple occurrences 155 | # (such as multiple spaces) 156 | while result.find(t) > -1: 157 | result = result.replace(t, "") 158 | return result 159 | 160 | if self.__doc is None: 161 | raise Exception("""You must parse the raw data, by calling a \ 162 | doc_xml_* method to populate the dom document object.""") 163 | 164 | result = [] 165 | for node in self.__doc.getElementsByTagName(self.base_node): 166 | temp = {} 167 | for tag in self.tags: 168 | temp[tag] = get_note_value(node.getElementsByTagName(tag), 169 | Node.TEXT_NODE) 170 | if not temp[tag]: 171 | temp[tag] = get_note_value(node.getElementsByTagName(tag), 172 | Node.CDATA_SECTION_NODE) 173 | result.append(temp) 174 | self.data = result 175 | 176 | def doc_xml_file(self, path): 177 | """ 178 | Parses a specified file into a xml.dom.minidom document object, to be 179 | used by `parse_data` method later on. This method here will store the 180 | result in the private `__doc` property. 181 | 182 | Arguments: 183 | 184 | * path: the XML file path that will be parsed into a dom 185 | document object. 186 | """ 187 | if not os.path.exists(path): 188 | raise exception.PathNotFoundException(path) 189 | 190 | try: 191 | self.__doc = parse(path) 192 | except: 193 | raise exception.XmlException(path) 194 | 195 | def doc_xml_string(self, text): 196 | """ 197 | Parses a specified string into a xml.dom.minidom document object, to be 198 | used by `parse_data` method later on. This method here will store the 199 | result in the private `__doc` property. 200 | 201 | Arguments: 202 | 203 | * text: the XML string value that will be parsed into a dom 204 | document object. 205 | """ 206 | try: 207 | self.__doc = parseString(text) 208 | except: 209 | raise exception.XmlException(text) 210 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/helper/urlfetcher.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: urlfetcher.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | A helper class used for screens that require Internet connectivity. See 29 | additional information in the class itself. 30 | 31 | The helper class available here is: 32 | 33 | * `URLFetcherHelperBase` 34 | 35 | """ 36 | 37 | import time 38 | from urllib.error import HTTPError, URLError 39 | from urllib.parse import urlparse, urlsplit, urlunsplit 40 | # 41 | # Python built-in modules 42 | # 43 | from urllib.request import Request, urlopen 44 | 45 | from termsaver.termsaverlib import constants, exception 46 | from termsaver.termsaverlib.i18n import _ 47 | # 48 | # Internal modules 49 | # 50 | from termsaver.termsaverlib.screen.helper import ScreenHelperBase 51 | 52 | 53 | class URLFetcherHelperBase(ScreenHelperBase): 54 | """ 55 | A helper class that provides Internet connectivity for termsaver screens. 56 | The functionalities available are: 57 | 58 | * fetch data over the Internet (only text-base) 59 | * avoid too many requests at a time (configured at 60 | `constants.Settings.FETCH_INTERVAL_SECONDS` 61 | 62 | For these functionalities, the following methods are publicly available: 63 | 64 | * `fetch`: for a specified URI, it returns its string contents 65 | additionally, this will also set a `raw` property with the data 66 | last fetched. 67 | 68 | * `fix_uri`: uses an algorithm to fix and validate a string as URL 69 | format. This should be used to prepare the URL before calling `fetch` 70 | method. 71 | 72 | """ 73 | 74 | __last_fetched = None 75 | """ 76 | A flag that defines the EPOCH time when the last fetch occurred, to ensure 77 | termsaver application does not keep connecting to the Internet without need 78 | 79 | See also: `constants.Settings.FETCH_INTERVAL_SECONDS` 80 | """ 81 | 82 | raw = "" 83 | """ 84 | The raw text data that is fetched using urllib. This can be later 85 | manipulated as needed (xml parsing, etc). 86 | """ 87 | 88 | def fix_uri(self, text): 89 | """ 90 | Validates a text as URL format, also adjusting necessary stuff for a 91 | clearer URL that will be fetched here. 92 | 93 | Code based on Django source: 94 | https://code.djangoproject.com/browser/django/trunk/django/forms/ 95 | fields.py?rev=17430#L610 96 | 97 | Arguments: 98 | 99 | * text: the URL string that is to be validated and fixed 100 | """ 101 | if not text: 102 | raise exception.UrlException(text, _("URL can not be blank")) 103 | try: 104 | url_fields = list(urlsplit(text)) 105 | except ValueError: 106 | raise exception.UrlException(text, _("URL does not seem valid")) 107 | 108 | if not url_fields[0]: 109 | # If no URL scheme given, assume http:// 110 | url_fields[0] = 'http' 111 | if not url_fields[1]: 112 | # Assume that if no domain is provided, that the path segment 113 | # contains the domain. 114 | url_fields[1] = url_fields[2] 115 | url_fields[2] = '' 116 | # Rebuild the url_fields list, since the domain segment may now 117 | # contain the path too. 118 | try: 119 | url_fields = list(urlsplit( 120 | urlunsplit(url_fields))) 121 | except ValueError: 122 | raise exception.UrlException(text, 123 | _("URL does not seem valid")) 124 | 125 | if not url_fields[2]: 126 | # the path portion may need to be added before query params 127 | url_fields[2] = '/' 128 | return urlunsplit(url_fields) 129 | 130 | def fetch(self, uri, method_override="POST", user_agent_override=None): 131 | """ 132 | Executes the fetch action toward a specified URI. This will also 133 | try to avoid unnecessary calls to the Internet by setting the flag 134 | `__last_fetched`. If it can not fetch again, it will simply return 135 | the `raw` data that was previously created by a previous fetch. 136 | 137 | Arguments: 138 | 139 | * uri: the path to be fetched 140 | """ 141 | # check if we can fetch again 142 | if self.__last_fetched and not self.raw and \ 143 | time.time() - self.__last_fetched < \ 144 | constants.Settings.FETCH_INTERVAL_SECONDS: 145 | return self.raw 146 | 147 | if not user_agent_override: 148 | headers = {'User-Agent': "%s/%s" % (constants.App.NAME, 149 | constants.App.VERSION)} 150 | else: 151 | headers = {'User-Agent': user_agent_override} 152 | url = uri 153 | data = None 154 | if method_override == "POST": 155 | # separate possible querystring data from plain URL 156 | temp = uri.split('?') 157 | url = temp[0] 158 | if len(temp) > 1: # old style condition for old python compatibility 159 | data = temp[1] 160 | else: 161 | data = None 162 | 163 | if data: 164 | data = data.encode('utf-8') 165 | 166 | self.log(_("Connecting to %s ... (this could take a while)") % uri) 167 | 168 | # execute URL fetch 169 | req = Request(url, data, headers, method=method_override) 170 | resp = None 171 | try: 172 | resp = urlopen(req) 173 | except HTTPError as e: 174 | raise exception.UrlException(uri, 175 | _("Fetched URL returned error %d.") % e.code) 176 | except URLError as e: 177 | raise exception.UrlException(uri, 178 | _("Could not fetch URL, because %s") % e.reason) 179 | else: 180 | self.__last_fetched = time.time() 181 | 182 | self.raw = resp.read() 183 | # make sure the content is not binary (eg. image) 184 | if self.__is_response_binary(self.raw): 185 | raise exception.UrlException(uri, _("Fetched data is binary.")) 186 | finally: 187 | if resp: 188 | resp.close() 189 | 190 | return self.raw 191 | 192 | def __is_response_binary(self, raw): 193 | """ 194 | Returns True if the given data is binary in nature, and False otherwise 195 | 196 | For the merit of being a binary file (i.e., termsaver will not be able 197 | to handle it), it is safe enough to consider the above True, as any 198 | files in this situation will be simply skipped, avoiding weird errors 199 | being thrown to the end-user. 200 | 201 | Arguments: 202 | 203 | raw: the response data that must be tested for binary values 204 | """ 205 | return raw.find(b'\0') > -1 206 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 30 | 31 | TermSaver 32 | ========= 33 | 34 | *A simple text-based screensaver for terminal windows.* 35 | 36 | ![termsaver](https://github.com/brunobraga/termsaver/raw/master/extras/termsaver-main_medium.jpeg) 37 | 38 | 39 | Background 40 | ---------- 41 | 42 | The motivation behind this project is basically pure boredom (laughs). 43 | Seriously, it may look like nonsense to have a screensaver look-alike program 44 | running on a terminal window. Nonetheless, sometimes, we still want to see some 45 | kind of movement, or action on the screen... which invigorates one's state of 46 | mind and helps concentration back to the black screen (well, some people like 47 | it white, meh!). 48 | 49 | If you are: 50 | 51 | * looking for some extra display on your main terminal window, to keep the 52 | screen busy while you are up to something else; or 53 | * looking for some distractions that may entertain you after too many hours 54 | in front of the terminal; or 55 | * with plenty of screen space (so long 80x25 default terminal window! long 56 | live 1920px...), and use many terminals on screen; or 57 | * just wanting to pretend you are busy with something (this is terrible) 58 | 59 | then, TermSaver is the **right** application for you. 60 | 61 | 62 | Requirements 63 | ------------ 64 | 65 | * Linux, or Mac (or Windows too, but you are on your own) 66 | * Python 3.x (Python 2.x was deprecated since 08-2020) 67 | 68 | 69 | Installation 70 | ------------ 71 | #### Pip (Pip Installs Packages, for Python Package Index) 72 | 73 | For those using others, and still want to do it the easy way, I recommend: 74 | 75 | sudo pip install termsaver 76 | 77 | 78 | #### From the Source 79 | 80 | For the brave (laughs), you can compile/install from the source: 81 | 82 | 1. Download the Source 83 | [here](http://pypi.python.org/pypi/termsaver/) or [here](https://github.com/brunobraga/termsaver/) 84 | 85 | 2. Unpack it 86 | 87 | tar -zxvf termsaver-{version}.tar.gz 88 | 89 | 3. Build it 90 | cd termsaver-{version}/ 91 | python -m build 92 | 93 | 3. Install it 94 | cd dist/ 95 | pip install termsaver-{version}-py3-none-any.whl 96 | 97 | 98 | Features 99 | -------- 100 | 101 | The TermSaver is a very simple application, built with the idea to allow more 102 | screensavers to be added to its core. Developers, please read the section below. 103 | 104 | The current published screensavers are: 105 | 106 | 107 | #### Ascii Art Farts 108 | 109 | This is a screensaver that displays ascii art from asciiartfarts.com 110 | RSS feed in an animation format. 111 | 112 | 113 | #### Clock 114 | 115 | This is a screensaver that displays a digital clock using ascii letters. 116 | 117 | 118 | #### Img2Ascii 119 | 120 | This is a screensaver that displays images using ascii letters. 121 | 122 | 123 | #### Jokes For All 124 | 125 | This is a screensaver that displays recent jokes from 126 | website, from its hourly updated [RSS](http://en.wikipedia.org/wiki/RSS) feed. 127 | 128 | 129 | #### Matrix 130 | 131 | This is a screensaver that displays falling (rising) Japanese characters 132 | simulating the screen from the movie 133 | [The Matrix](http://en.wikipedia.org/wiki/The_Matrix). 134 | 135 | 136 | #### Programmer 137 | 138 | This is a screensaver that displays source code from a specified path in 139 | visual animation. If the [pygments](https://pygments.org/) package is installed, this screensaver 140 | will apply syntax highlighting based on the file type. 141 | 142 | #### Quotes For All 143 | 144 | This is a screensaver that displays recent quotes from 145 | website, from its hourly updated [RSS](http://en.wikipedia.org/wiki/RSS) feed. 146 | 147 | 148 | #### Random Text 149 | 150 | This is a screensaver that displays a text (your name, or whatever) on a 151 | randomized position of the screen, changing position every N seconds. 152 | 153 | 154 | #### Request for Comments 155 | 156 | This is a screensaver that fetches documents from RFC (Request for Comments) 157 | in visual animation, which are documents elaborated by the Internet 158 | Engineering Task Force, available at . This 159 | screensaver randomizes documents to display, from a list of latest valid 160 | documents. See more information about this in 161 | [Wikipedia](http://en.wikipedia.org/wiki/Request_for_Comments). 162 | 163 | 164 | #### RSS Feeds 165 | 166 | This is a screensaver that displays any 167 | [RSS](http://en.wikipedia.org/wiki/RSS) feed you want to show in your 168 | terminal, with customizable settings and format. 169 | 170 | 171 | #### URL Fetcher 172 | 173 | This is a screensaver that displays content from a specified 174 | [URL](http://en.wikipedia.org/wiki/Uniform_resource_locator) directly 175 | on screen, in visual animation. 176 | 177 | 178 | #### Star Wars Asciimation 179 | 180 | This is a screensaver that displays the Star Wars Asciimation from 181 | . 182 | 183 | 184 | #### Sysmon 185 | 186 | (For Linux/Mac systems only) Displays the CPU/Memory usage over time in a graphic 187 | alike screensaver. 188 | 189 | #### WWTR.IN 190 | 191 | Shows weather information from [wttr.in](https://www.wttr.in/) 192 | 193 | - - - 194 | 195 | **Disclaimer Note**: termsaver holds no responsibility for the contents offered 196 | by third-parties, nor it has controls to filter them. Use it at your own risk. 197 | 198 | 199 | Developers 200 | ---------- 201 | 202 | A more detailed guideline for developers willing to jump in and create 203 | screensavers for termsaver is here: 204 | 205 | 206 | Roadmap 207 | ------- 208 | 209 | There is no current roadmap defined, besides improvement tickets created in 210 | [Issues](https://github.com/brunobraga/termsaver/issues) tab in GitHub. 211 | Refer also to for 212 | some insights of stuff we are thinking about. 213 | 214 | Contribute 215 | ---------- 216 | 217 | ### Translation 218 | 219 | The internationalization of this application follows same standards of most 220 | applications out there, by using *gettext* and MO/PO files. 221 | 222 | The translation is still being finished up, and when it is ready for 223 | contributor calls, we will post detailed information about the procedure. 224 | 225 | 226 | ### Screensavers (plugin) 227 | 228 | As of v0.2, full plugin support is available, find an example here: 229 | 230 | https://github.com/brunobraga/termsaver-figlet 231 | 232 | 233 | ### Submit a bug 234 | 235 | If you find any errors in this application, you are more than welcome to 236 | participate. You can: 237 | 238 | * report the bug: 239 | 240 | * Fork this project: 241 | 242 | Uninstall 243 | ---------- 244 | 245 | ### Using Pip (Pip Install Packages, for Python Package Index) 246 | 247 | sudo pip uninstall termsaver 248 | 249 | 250 | ### Manual Uninstall 251 | 252 | Just remove manually the following files: 253 | 254 | # For Linux boxes 255 | rm -rvf /usr/local/bin/termsaver 256 | 257 | # change your python version/location here 258 | rm -rvf /usr/local/lib/python3.x/dist-packages/termsaver* 259 | 260 | rm -rvf /usr/local/share/man/man1/termsaver.1 261 | find /usr/local/share/locale/ -name "termsaver.mo" -exec rm -rfv {} \; 262 | 263 | If the actuall location differ from the above, it might be worth it to just 264 | run the find command and look for them yourself (should not be hard): 265 | 266 | find /usr/ -name "*termsaver*" 267 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/common.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: common.py 4 | # 5 | # Purpose: holds common helper functions used by termsaver code. 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | Holds common functionality used by termsaver screens. 29 | """ 30 | 31 | # 32 | # Python build-in modules 33 | # 34 | import os 35 | import sys 36 | import traceback 37 | from html.parser import HTMLParser 38 | import subprocess 39 | import re 40 | import time 41 | 42 | 43 | def is_windows(): 44 | """ 45 | Returns True if the environment is Microsoft Windows. 46 | """ 47 | return sys.platform == "win32" 48 | 49 | 50 | def is_macos(): 51 | """ 52 | Returns True if the environment is Microsoft Windows. 53 | """ 54 | return sys.platform == "darwin" 55 | 56 | 57 | def prettify_exception(ex): 58 | """ 59 | Outputs the exception with its stack trace within separator lines. 60 | """ 61 | error_message = "" 62 | if hasattr(ex, 'message'): 63 | error_message = ex.message 64 | else: 65 | error_message = ex 66 | print (""" 67 | =================================== 68 | Exception: (%s) %s 69 | %s 70 | =================================== 71 | """ % (ex.__class__.__name__, error_message, traceback.format_exc())) 72 | 73 | 74 | def get_app_dir(): 75 | """ 76 | Retrieves the termsaver main directory based on current operating system. 77 | 78 | For Windows machines, this should be something like: 79 | 80 | \Documents and Settings\\Application Data\termsaver 81 | 82 | For Unix machines, it will be: 83 | 84 | /home//.termsaver/ 85 | """ 86 | if is_windows(): 87 | path = os.path.join(os.environ['APPDATA'], "termsaver") 88 | else: 89 | path = os.path.join(os.environ['HOME'], ".termsaver") 90 | 91 | # create if applicable 92 | if not os.path.exists(path): 93 | # permission errors here will just propagate error 94 | os.mkdir(path) 95 | 96 | return path 97 | 98 | 99 | def get_temp_dir(): 100 | """ 101 | Retrieves the temporary based on current operating system. 102 | 103 | For Windows machines, this should be something like: 104 | 105 | \Documents and Settings\\Local Settings\Temp 106 | 107 | For Unix machines, it will be: 108 | 109 | /tmp/ 110 | 111 | """ 112 | if is_windows(): 113 | path = os.environ['TMP'] 114 | else: 115 | path = "/tmp" 116 | 117 | return path 118 | 119 | 120 | def unescape_string(escaped_text): 121 | """ 122 | Unescape strings. This is useful for cases when data that needs to be 123 | displayed on screen is escaped for HTML or database stuff. 124 | 125 | Additional replacing is taken here, such as some HTML tags: 126 | 127 | *
, replaced to \n 128 | """ 129 | unescaped = escaped_text 130 | try: 131 | unescaped = HTMLParser.HTMLParser().unescape(escaped_text) 132 | # replace most common HTML data 133 | unescaped = unescaped.replace('
', '\n') 134 | unescaped = unescaped.replace('
', '\n') 135 | unescaped = unescaped.replace('
', '\n') 136 | # unescaped = unescaped.decode('string_escape') 137 | except: 138 | # 139 | # If there were errors here, just ignore them and try to give back 140 | # the string the best it could do 141 | # 142 | pass 143 | return unescaped 144 | 145 | 146 | def get_day_suffix(day): 147 | """ 148 | Returns the suffix of the day, such as in 1st, 2nd, ... 149 | """ 150 | if day in (1, 21, 31): 151 | return 'st' 152 | elif day in (2, 12, 22): 153 | return 'nd' 154 | elif day in (3, 23): 155 | return 'rd' 156 | else: 157 | return 'th' 158 | 159 | 160 | def execute_shell(cmd, ignore_errors=False): 161 | """ 162 | Simple routine to execute shell commands. 163 | If `ignore_errors` is false (default) errors here will be thrown, and 164 | must be treated individually, to ensure proper message to end-user. 165 | 166 | The `cmd` argument must be an array, formatted for subprocess.Popen. 167 | If you are not sure on how to do that, just use: shlex.split(string). 168 | """ 169 | try: 170 | p = subprocess.Popen(cmd, stdin=subprocess.PIPE, 171 | stdout=subprocess.PIPE, close_fds=True) 172 | out, __ = p.communicate() 173 | except Exception as e: 174 | if not ignore_errors: 175 | raise e 176 | return out.rstrip() 177 | 178 | 179 | def strip_html(text): 180 | """ 181 | Simple regex that cleans a string of any HTML tags (for terminal output, 182 | there isn't much sense to have them printed anyway). 183 | """ 184 | return re.sub('<[^<]+?>', '', text) 185 | 186 | 187 | def get_cpu_usage(sleep_delay, ignore_errors=False): 188 | """ 189 | """ 190 | try: 191 | if is_windows(): 192 | raise Exception(_("Functionality not available for Windows. See --help for details.")) 193 | 194 | elif is_macos(): 195 | ps = subprocess.Popen(['ps', '-A', '-o %cpu'], stdout=subprocess.PIPE) 196 | cpu = subprocess.check_output(('awk', '{s+=$1} END {print s "%"}'), stdin=ps.stdout) 197 | ps.wait() 198 | time.sleep(sleep_delay) # required to simulate same in linux 199 | return float(cpu.strip()[:-1]) 200 | 201 | else: 202 | # linux 203 | def getTimeList(): 204 | statFile = open("/proc/stat", "r") 205 | timeList = statFile.readline().split(" ")[2:6] 206 | statFile.close() 207 | for i in range(len(timeList)) : 208 | timeList[i] = int(timeList[i]) 209 | return timeList 210 | def deltaTime() : 211 | x = getTimeList() 212 | time.sleep(sleep_delay) 213 | y = getTimeList() 214 | for i in range(len(x)) : 215 | y[i] -= x[i] 216 | return y 217 | dt = deltaTime() 218 | if sum(dt) > 0: 219 | cpu = 100 - (dt[len(dt) - 1] * 100.00 / sum(dt)) 220 | else: 221 | cpu = 0 222 | 223 | return cpu 224 | 225 | except Exception as e: 226 | if not ignore_errors: 227 | raise e 228 | else: 229 | return 0 230 | 231 | 232 | def get_mem_usage(ignore_errors=False): 233 | """ 234 | """ 235 | try: 236 | if is_windows(): 237 | raise Exception(_("Functionality not available for Windows. See --help for details.")) 238 | 239 | elif is_macos(): 240 | 241 | vm = subprocess.Popen(['vm_stat'], stdout=subprocess.PIPE).communicate()[0] #.decode() 242 | vmLines = vm.split('\n') 243 | sep = re.compile(':[\s]+') 244 | vmStats = {} 245 | for row in range(1,len(vmLines)-2): 246 | rowText = vmLines[row].strip() 247 | rowElements = sep.split(rowText) 248 | vmStats[(rowElements[0])] = int(rowElements[1].strip('\.')) * 4096 249 | 250 | total_mem = (vmStats["Pages wired down"]+vmStats["Pages active"]+vmStats["Pages inactive"]+vmStats["Pages free"])/1024/1024 251 | curr_mem = (vmStats["Pages inactive"]+vmStats["Pages free"]) * 100 / (vmStats["Pages wired down"]+vmStats["Pages active"]+vmStats["Pages inactive"]+vmStats["Pages free"]) 252 | 253 | return (curr_mem, total_mem) 254 | 255 | else: 256 | # linux 257 | re_parser = re.compile(r'^(?P\S*):\s*(?P\d*)\s*kB') 258 | mem_info = {} 259 | for line in open('/proc/meminfo'): 260 | match = re_parser.match(line) 261 | if not match: 262 | continue # skip lines that don't parse 263 | key, value = match.groups(['key', 'value']) 264 | if key not in ('MemTotal', 'MemFree'): 265 | continue 266 | mem_info[key] = int(value) 267 | 268 | total_mem = mem_info['MemTotal'] / 1024 269 | curr_mem = (mem_info['MemTotal'] - mem_info['MemFree']) * 100 / mem_info['MemTotal'] 270 | 271 | return (curr_mem, total_mem) 272 | 273 | except Exception as e: 274 | if not ignore_errors: 275 | raise e 276 | else: 277 | return (0,0) 278 | 279 | 280 | 281 | 282 | -------------------------------------------------------------------------------- /extras/README.dist: -------------------------------------------------------------------------------- 1 | .. ############################################################################ 2 | .. # 3 | .. # file: README 4 | .. # 5 | .. # Purpose: holds basic information about termsaver application, 6 | .. # in markdown format for GitHub. 7 | .. # 8 | .. # Note: This file is part of Termsaver application, and should not be 9 | .. # used or executed separately. 10 | .. # 11 | .. ############################################################################ 12 | .. # 13 | .. # Copyright 2012 Termsaver 14 | .. # 15 | .. # Licensed under the Apache License, Version 2.0 (the "License"); you may 16 | .. # not use this file except in compliance with the License. You may obtain 17 | .. # a copy of the License at 18 | .. # 19 | .. # http://www.apache.org/licenses/LICENSE-2.0 20 | .. # 21 | .. # Unless required by applicable law or agreed to in writing, software 22 | .. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 23 | .. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 24 | .. # License for the specific language governing permissions and limitations 25 | .. # under the License. 26 | .. # 27 | .. ############################################################################ 28 | 29 | ========= 30 | TermSaver 31 | ========= 32 | 33 | *A simple text-based screensaver for terminal windows.* 34 | 35 | You may also want to visit our website: http://termsaver.brunobraga.net 36 | 37 | 38 | .. image:: https://github.com/brunobraga/termsaver/raw/master/extras/termsaver-main_medium.jpeg 39 | 40 | 41 | ---------- 42 | Background 43 | ---------- 44 | 45 | The motivation behind this project is basically pure boredom (laughs). 46 | Seriously, it may look like nonsense to have a screensaver look-alike program 47 | running on a terminal window. Nonetheless, sometimes, we still want to see some 48 | kind of movement, or action on the screen... which invigorates one's state of 49 | mind and helps concentration back to the black screen (well, some people like 50 | it white, meh!). 51 | 52 | If you are: 53 | 54 | * looking for some extra display on your main terminal window, to keep the 55 | screen busy while you are up to something else; or 56 | * looking for some distractions that may entertain you after too many hours 57 | in front of the terminal; or 58 | * with plenty of screen space (so long 80x25 default terminal window! long 59 | live 1920px...), and use many terminals on screen; or 60 | * just wanting to pretend you are busy with something (this is terrible) 61 | 62 | then, TermSaver is the **right** application for you. 63 | 64 | 65 | ------------ 66 | Requirements 67 | ------------ 68 | 69 | * Linux, or Mac (or Windows too, but you are on your own) 70 | * Python 3.x (Python 2.x was deprecated since 08-2020) 71 | 72 | 73 | 74 | ------------ 75 | Installation 76 | ------------ 77 | 78 | Apt (Advanced Packaging Tool) 79 | ----------------------------- 80 | 81 | For Ubuntu (12.10+) distro, you can use: 82 | 83 | :: 84 | 85 | sudo apt-get install termsaver 86 | 87 | Pip (Pip Installs Packages, for Python Package Index) 88 | ----------------------------------------------------- 89 | 90 | For those using others, and still want to do it the easy way, I recommend: 91 | 92 | :: 93 | 94 | sudo pip install termsaver 95 | 96 | 97 | From the Source 98 | --------------- 99 | 100 | 1. Download the Source here_: 101 | 102 | .. _here: http://pypi.python.org/pypi/termsaver/ 103 | 104 | 2. Unpack it 105 | 106 | :: 107 | 108 | tar -zxvf termsaver-{version}.tar.gz 109 | 110 | 3. Install it 111 | 112 | :: 113 | 114 | sudo python setup.py install 115 | 116 | PPA (Advanced Packaging Tool) 117 | ----------------------------- 118 | 119 | If you can't wait for Debian/Ubuntu releases, you can get the latest packages from: 120 | 121 | :: 122 | 123 | 124 | sudo add-apt-repository ppa:bruno-braga/termsaver 125 | sudo apt-get update 126 | sudo apt-get install termsaver 127 | 128 | 129 | -------- 130 | Features 131 | -------- 132 | 133 | The TermSaver is a very simple application, built with the idea to allow more 134 | screensavers to be added to its core. Developers, please read the section below. 135 | 136 | The current published screensavers are: 137 | 138 | Ascii Art Farts 139 | --------------- 140 | 141 | This is a screensaver that displays ascii art from asciiartfarts.com 142 | RSS feed in an animation format. 143 | 144 | Image 2 Ascii 145 | ------------- 146 | 147 | This is a screensaver that converts images or folders of images into 148 | ascii art. 149 | 150 | Jokes For All 151 | ------------- 152 | 153 | This is a screensaver that displays recent jokes from http://jokes4all.net 154 | website, from its hourly updated RSS_ feed. 155 | 156 | .. _RSS : http://en.wikipedia.org/wiki/RSS 157 | 158 | Programmer 159 | ---------- 160 | 161 | This is a screensaver that displays source code from a specified path in 162 | visual animation. If pygments is installed then it will apply syntax 163 | highlighting based on the file type. 164 | 165 | Quotes For All 166 | -------------- 167 | 168 | This is a screensaver that displays recent quotes from http://quotes4all.net 169 | website, from its hourly updated RSS_ feed. 170 | 171 | .. _RSS : http://en.wikipedia.org/wiki/RSS 172 | 173 | Random Text 174 | ----------- 175 | 176 | This is a screensaver that displays a text (your name, or whatever) on a 177 | randomized position of the screen, changing position every N seconds. 178 | 179 | Request for Change 180 | ------------------ 181 | 182 | This is a screensaver that fetches documents from RFC (Request for Comments) 183 | in visual animation, which are documents elaborated by the Internet 184 | Engineering Task Force, available at http://tools.ietf.org/rfc/. This 185 | screensaver randomizes documents to display, from a list of latest valid 186 | documents. See more information about this in Wikipedia_. 187 | 188 | .. _Wikipedia : http://en.wikipedia.org/wiki/Request_for_Comments 189 | 190 | 191 | RSS Feeds 192 | --------- 193 | 194 | This is a screensaver that displays any 195 | RSS_ feed you want to show in your terminal, with customizable settings 196 | and format. 197 | 198 | .. _RSS : http://en.wikipedia.org/wiki/RSS 199 | 200 | URL Fetcher 201 | ----------- 202 | 203 | This is a screensaver that displays content from a specified 204 | URL_ directly on screen, in visual animation. 205 | 206 | .. _URL : http://en.wikipedia.org/wiki/Uniform_resource_locator 207 | 208 | Clock 209 | ----- 210 | 211 | This is a screensaver that displays a digital clock using ascii letters. 212 | 213 | Matrix 214 | ------ 215 | 216 | This is a screensaver that displays falling (rising) Japanese characters 217 | simulating the screen from the movie The_Matrix_ 218 | 219 | .. _The_Matrix : http://en.wikipedia.org/wiki/The_Matrix 220 | 221 | Sysmon 222 | ------ 223 | 224 | (For Linux/Mac systems only) Displays the CPU/Memory usage over time in a graphic 225 | alike screensaver. 226 | 227 | Starwars 228 | ------ 229 | 230 | Displays the Star Wars Asciimation from http://asciimation.co.nz. 231 | 232 | ------ 233 | 234 | **Disclaimer Note**: termsaver holds no responsibility for the contents offered 235 | by third-parties, nor it has controls to filter them. Use it at your own risk. 236 | 237 | 238 | ---------- 239 | Developers 240 | ---------- 241 | 242 | A more detailed guideline for developers willing to jump in and create 243 | screensavers for termsaver is here: https://github.com/brunobraga/termsaver/wiki/Developers 244 | 245 | 246 | ------- 247 | Roadmap 248 | ------- 249 | 250 | There is no current roadmap defined, besides improvement tickets created in 251 | Issues_ tab in GitHub. 252 | Refer also to http://github.com/brunobraga/termsaver/wiki/Brainstorming for 253 | some insights of stuff we are thinking about. 254 | 255 | .. _Issues : https://github.com/brunobraga/termsaver/issues 256 | 257 | ---------- 258 | Contribute 259 | ---------- 260 | 261 | Translation 262 | ----------- 263 | 264 | The internationalization of this application follows same standards of most 265 | applications out there, by using *gettext* and MO/PO files. 266 | 267 | The translation is still being finished up, and when it is ready for 268 | contributor calls, we will post detailed information about the procedure. 269 | 270 | 271 | Screensavers (plugin) 272 | --------------------- 273 | 274 | As of v0.2, full plugin support is available, find an example here: 275 | 276 | https://github.com/brunobraga/termsaver-figlet 277 | 278 | 279 | Submit a bug 280 | ------------ 281 | 282 | If you find any errors in this application, you are more than welcome to 283 | participate. You can: 284 | 285 | * report the bug: https://github.com/brunobraga/termsaver/issues 286 | 287 | * Fork this project: https://github.com/brunobraga/termsaver/fork 288 | 289 | 290 | --------- 291 | Uninstall 292 | --------- 293 | 294 | Using Apt (Advanced Packaging Tool) or PPA (Personal Package Archive) 295 | ---------------------------------------------------------------------- 296 | 297 | :: 298 | 299 | sudo apt-get remove termsaver 300 | 301 | 302 | Using Pip (Pip Install Packages, for Python Package Index) 303 | ---------------------------------------------------------- 304 | 305 | :: 306 | 307 | sudo pip uninstall termsaver 308 | 309 | 310 | Manual Uninstall 311 | ---------------- 312 | 313 | Just remove manually the following files: 314 | 315 | :: 316 | 317 | # For Linux boxes 318 | rm -rvf /usr/local/bin/termsaver 319 | 320 | # change this to point to your Python version 321 | rm -rvf /usr/local/lib/python3.x/dist-packages/termsaver* 322 | 323 | rm -rvf /usr/local/share/man/man1/termsaver.1 324 | find /usr/local/share/locale/ -name "termsaver.mo" -exec rm -rfv {} \; 325 | 326 | If the actuall location differ from the above, it might be worth it to just 327 | run the find command and look for them yourself (should not be hard): 328 | 329 | :: 330 | 331 | find /usr/ -name "*termsaver*" 332 | -------------------------------------------------------------------------------- /termsaver/termsaverlib/screen/base/rssfeed.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # 3 | # file: rssfeed.py 4 | # 5 | # Purpose: refer to module documentation for details 6 | # 7 | # Note: This file is part of Termsaver application, and should not be used 8 | # or executed separately. 9 | # 10 | ############################################################################### 11 | # 12 | # Copyright 2012 Termsaver 13 | # 14 | # Licensed under the Apache License, Version 2.0 (the "License"); you may 15 | # not use this file except in compliance with the License. You may obtain 16 | # a copy of the License at 17 | # 18 | # http://www.apache.org/licenses/LICENSE-2.0 19 | # 20 | # Unless required by applicable law or agreed to in writing, software 21 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 22 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 23 | # License for the specific language governing permissions and limitations 24 | # under the License. 25 | # 26 | ############################################################################### 27 | """ 28 | This module contains a screen base class that handles RSS feeds display. 29 | See additional information in the class itself. 30 | 31 | The helper classes available here are: 32 | 33 | * `RSSFeedScreenBase` 34 | * `SimpleRSSFeedScreenBase` 35 | """ 36 | 37 | # 38 | # Python built-in modules 39 | # 40 | import time 41 | 42 | from termsaver.termsaverlib import common, constants, exception 43 | from termsaver.termsaverlib.i18n import _ 44 | # 45 | # Internal modules 46 | # 47 | from termsaver.termsaverlib.screen.base import ScreenBase 48 | from termsaver.termsaverlib.screen.base.urlfetcher import UrlFetcherBase 49 | from termsaver.termsaverlib.screen.helper.position import PositionHelperBase 50 | from termsaver.termsaverlib.screen.helper.typing import TypingHelperBase 51 | from termsaver.termsaverlib.screen.helper.xmlreader import XMLReaderHelperBase 52 | 53 | 54 | class RSSFeedScreenBase(UrlFetcherBase, 55 | TypingHelperBase, 56 | PositionHelperBase, 57 | XMLReaderHelperBase): 58 | """ 59 | A base class used to handle RSS feeds, and display them accordingly. 60 | This also includes the `TypingHelperBase` and `PositionHelperBase` to 61 | add functionality of typing writer display, and certain positioning 62 | features. 63 | 64 | The instantiation of this class takes two additional arguments, compared 65 | with its base class: 66 | 67 | * tags: defines the list of string tags of the RSS that you are 68 | interest in. Accepted values are: 69 | * pubDate 70 | * title 71 | * link 72 | * description 73 | 74 | * print_format: defines the formating to be printed out, based on 75 | the tags available (use python string format with dictionary. eg. 76 | '%(title)s (%(pubDate)s)\n\n') 77 | 78 | When inheriting from this screen, you can also take advantage of the 79 | following properties and functionalities: 80 | 81 | * `sleep_between_items`: Sleeping time, in seconds, between each RSS 82 | item displayed. 83 | 84 | * `cleanup_per_item`: Defines if termsaver should clean the screen for 85 | each item being read 86 | 87 | * `center_vertically`: Defines if the information displayed should be 88 | vertically centered on screen. 89 | 90 | * `center_horizontally`: Defines if the information displayed should be 91 | horizontally centered on screen. 92 | """ 93 | 94 | sleep_between_items = 1 95 | """ 96 | Sleeping time, in seconds, between each RSS item displayed. 97 | """ 98 | 99 | cleanup_per_item = False 100 | """ 101 | Defines if termsaver should clean the screen for each item being read 102 | """ 103 | 104 | center_vertically = False 105 | """ 106 | Defines if the information displayed should be vertically centered on 107 | screen. 108 | """ 109 | 110 | center_horizontally = False 111 | """ 112 | Defines if the information displayed should be horizontally centered on 113 | screen. 114 | """ 115 | 116 | clean_html = True 117 | """ 118 | Defines that the output text must be cleaned from HTML tags. 119 | """ 120 | 121 | def __init__(self, parser, url=None, 122 | tags=None, print_format=None, delay=None): 123 | """ 124 | Creates a new instance of this class. 125 | 126 | This constructor has two additional arguments, compared with its base 127 | class: 128 | 129 | * tags: defines the list of string tags of the RSS that you are 130 | interest in. Accepted values are: 131 | * pubDate 132 | * title 133 | * link 134 | * description 135 | 136 | * print_format: defines the formating to be printed out, based on 137 | the tags available (use python string format with dictionary. eg. 138 | '%(title)s (%(pubDate)s)\n\n') 139 | """ 140 | 141 | UrlFetcherBase.__init__(self, parser, url, delay) 142 | XMLReaderHelperBase.__init__(self, "item", tags) 143 | 144 | if self.parser != None: 145 | self.parser.add_argument("-u", "--url", help="The rss feed url", type=str) 146 | self.parser.add_argument("-r", "--raw", help="Shows all text available (with HTML if any)", action="store_true") 147 | 148 | #if not hasFormat: 149 | self.parser.add_argument("-f", "--format",type=str, action="store", help="""|R 150 | The printing format according to values available in RSS feed: 151 | * pubDate 152 | * title 153 | * link 154 | * description 155 | You must use python dictionary based formatting style 156 | (see examples for details)""") 157 | 158 | self.print_format = print_format 159 | if not print_format: 160 | self.print_format = '%(title)s (%(pubDate)s)\n\n' 161 | 162 | def _parse_args(self, launchScreenImmediately=True): 163 | """ 164 | Handles the special command-line arguments available for this screen. 165 | Although this is a base screen, having these options prepared here 166 | can save coding for screens that will not change the default options. 167 | 168 | See `_usage_options_example` method for documentation on each of the 169 | options being parsed here. 170 | 171 | Additionally, this is dependent on the values exposed in `cli_opts`, 172 | passed to this class during its instantiation. Only values properly 173 | configured there will be accepted here. 174 | """ 175 | args, unknown = self.parser.parse_known_args() 176 | 177 | if args.raw: 178 | self.clean_html = False 179 | 180 | if args.format: 181 | self.print_format = common.unescape_string(args.format) 182 | 183 | if args.url: 184 | try: 185 | # try to fix the url formatting 186 | self.url = self.fix_uri(args.url) 187 | except Exception as e: 188 | error_message = "" 189 | if hasattr(e, 'message'): 190 | error_message = e.message 191 | else: 192 | error_message = e 193 | raise exception.InvalidOptionException("url", error_message) 194 | else: 195 | raise exception.InvalidOptionException("url", "URL is required") 196 | 197 | if launchScreenImmediately: 198 | self.autorun() 199 | else: 200 | return self 201 | 202 | def _run_cycle(self): 203 | """ 204 | Executes a cycle of this screen. 205 | 206 | The actions taken here, for each cycle, are as follows: 207 | 208 | * retrieve data from `url` 209 | * parses the data into a XML dom document object 210 | * parses the document object into a list of dictionaries 211 | * print using `typing_print` 212 | """ 213 | self.doc_xml_string(self.fetch(self.url)) 214 | self.parse_data() 215 | self.clear_screen() 216 | 217 | for item in self.data: 218 | new_text = item 219 | try: 220 | new_text = common.unescape_string(self.print_format % new_text) 221 | # remove HTML tags is applicable 222 | if self.clean_html: 223 | new_text = common.strip_html(new_text) 224 | except: 225 | raise exception.InvalidOptionException("format", 226 | _("There was an error while using your format.")) 227 | 228 | if self.center_vertically or self.center_horizontally: 229 | self.get_terminal_size() 230 | 231 | if self.center_vertically: 232 | new_text = self.center_text_vertically(new_text) 233 | if self.center_horizontally: 234 | new_text = self.center_text_horizontally(new_text) 235 | 236 | self.typing_print(new_text) 237 | time.sleep(self.sleep_between_items) 238 | 239 | if self.cleanup_per_item: 240 | self.clear_screen() 241 | 242 | 243 | class SimpleRSSFeedScreenBase(ScreenBase, RSSFeedScreenBase): 244 | """ 245 | Inherits the `RSSFeedScreenBase` class to handle basic RSS parsing. 246 | This will simplify the use of RSSFeedScreenBase by forcing a fixed 247 | URL feed, and simplify the code of screens inheriting from it. 248 | """ 249 | 250 | def __init__(self, name, description, parser, url, 251 | tags=None, print_format=None, delay=None): 252 | """ 253 | Creates a new instance of this class. 254 | 255 | This constructor has forced the url argument, compared with its base 256 | class, as it has no command line options to define its value manually 257 | """ 258 | ScreenBase.__init__(self, name, description, parser) 259 | RSSFeedScreenBase.__init__(self, 260 | parser, url, tags, 261 | print_format, delay 262 | ) 263 | 264 | def _run_cycle(self): 265 | RSSFeedScreenBase._run_cycle(self) 266 | -------------------------------------------------------------------------------- /locale/ja/LC_MESSAGES/termsaver.po: -------------------------------------------------------------------------------- 1 | # Japanese translations for PACKAGE package. 2 | # Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # Automatically generated, 2012. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PACKAGE VERSION\n" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2012-03-01 22:35+1000\n" 11 | "PO-Revision-Date: 2012-03-01 22:35+1000\n" 12 | "Last-Translator: Automatically generated\n" 13 | "Language-Team: none\n" 14 | "Language: ja\n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=UTF-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Plural-Forms: nplurals=1; plural=0;\n" 19 | 20 | #: termsaverlib/screen/quotes4all.py:86 21 | msgid "displays recent quotes from quotes4all.net" 22 | msgstr "quotes4all.netから最近の引用符が表示されます。" 23 | 24 | #: termsaverlib/screen/asciiartfarts.py:82 25 | msgid "displays ascii images from asciiartfarts.com (NSFW)" 26 | msgstr "" 27 | 28 | #: termsaverlib/screen/rssfeed.py:74 29 | msgid "displays rss feed information" 30 | msgstr "" 31 | 32 | #: termsaverlib/screen/rssfeed.py:91 33 | #, python-format 34 | msgid "" 35 | "\n" 36 | "You just need to provide the URL of the RSS feed from where %(app_title)s will\n" 37 | "read and display on screen.\n" 38 | "\n" 39 | "If you do not have any idea which RSS to use, check out some examples here:\n" 40 | "\n" 41 | " CNN\n" 42 | " Top Stories - http://rss.cnn.com/rss/edition.rss\n" 43 | " World - http://rss.cnn.com/rss/edition_world.rss\n" 44 | " Technology - http://rss.cnn.com/rss/edition_technology.rss\n" 45 | "\n" 46 | " See CNN's complete list of RSS syndication here:\n" 47 | " http://edition.cnn.com/services/rss/\n" 48 | "\n" 49 | " Lifehacker - http://www.lifehacker.com/index.xml\n" 50 | " Note: Lifehacker uses HTML to deliver \"description\" contents in the RSS,\n" 51 | " so you might need to change the format to something like:\n" 52 | " --format \"%%(title)s (%%(pubDate)s)\\n\"\n" 53 | msgstr "" 54 | 55 | #: termsaverlib/screen/helper/urlfetcher.py:101 56 | msgid "URL can not be blank" 57 | msgstr "" 58 | 59 | #: termsaverlib/screen/helper/urlfetcher.py:105 60 | #: termsaverlib/screen/helper/urlfetcher.py:122 61 | msgid "URL does not seem valid" 62 | msgstr "" 63 | 64 | #: termsaverlib/screen/helper/urlfetcher.py:156 65 | #, python-format 66 | msgid "Connecting to %s ... (this could take a while)" 67 | msgstr "" 68 | 69 | #: termsaverlib/screen/helper/urlfetcher.py:164 70 | #, python-format 71 | msgid "Fetched URL returned error %d." 72 | msgstr "" 73 | 74 | #: termsaverlib/screen/helper/urlfetcher.py:167 75 | #, python-format 76 | msgid "Could not fetch URL, because %s" 77 | msgstr "" 78 | 79 | #: termsaverlib/screen/helper/urlfetcher.py:175 80 | msgid "Fetched data is binary." 81 | msgstr "" 82 | 83 | #: termsaverlib/screen/randtxt.py:87 84 | msgid "displays word in random places on screen" 85 | msgstr "" 86 | 87 | #: termsaverlib/screen/randtxt.py:126 88 | #, python-format 89 | msgid "" 90 | "\n" 91 | "Options:\n" 92 | "\n" 93 | " -w, --word Sets the word to be displayed\n" 94 | " default is the name of this application\n" 95 | " -d, --delay Sets how long the word will be displayed before\n" 96 | " randomized again. Default is%(default_delay)s of a second\n" 97 | " -h, --help Displays this help message\n" 98 | "\n" 99 | "Example:\n" 100 | "\n" 101 | " $ %(app_name)s %(screen)s\n" 102 | " This will trigger the screensaver to display the default word %(app_title)s\n" 103 | " in random locations of the screen\n" 104 | "\n" 105 | " $ %(app_name)s %(screen)s -w FooBar\n" 106 | " This will trigger the screensaver to display the default word FooBar\n" 107 | " in random locations of the screen\n" 108 | msgstr "" 109 | 110 | #: termsaverlib/screen/randtxt.py:181 termsaverlib/screen/base/rssfeed.py:220 111 | #: termsaverlib/screen/base/rssfeed.py:323 112 | #: termsaverlib/screen/base/filereader.py:209 113 | #: termsaverlib/screen/base/urlfetcher.py:179 114 | #: termsaverlib/screen/base/urlfetcher.py:240 termsaverlib/screen/dot.py:175 115 | msgid "Unhandled option. See --help for details." 116 | msgstr "" 117 | 118 | #: termsaverlib/screen/base/__init__.py:304 119 | #, python-format 120 | msgid "" 121 | "Screen: %(screen)s\n" 122 | "Description: %(description)s\n" 123 | "\n" 124 | "Usage: %(app_name)s %(screen)s [options]" 125 | msgstr "" 126 | 127 | #: termsaverlib/screen/base/rssfeed.py:162 128 | #, python-format 129 | msgid "" 130 | "\n" 131 | "Options:\n" 132 | "\n" 133 | " -h, --help Displays this help message\n" 134 | " -u, --url The URL path of the RSS feed (text) to be displayed\n" 135 | " -f, --format The printing format according to values available in RSS feed:\n" 136 | " * pubDate\n" 137 | " * title\n" 138 | " * link\n" 139 | " * description\n" 140 | " You must use python dictionary based formatting style\n" 141 | " (see examples for details)\n" 142 | "\n" 143 | "Example:\n" 144 | "\n" 145 | " $ %(app_name)s %(screen)s -u http://rss.cnn.com/rss/edition.rss\n" 146 | " This will trigger the screensaver to fetch the contents from the CNN feed\n" 147 | " and display it in default formatting: '%%(title)s (%%(pubDate)s)\\n'\n" 148 | "\n" 149 | " $ %(app_name)s %(screen)s -u http://rss.cnn.com/rss/edition.rss \\\n" 150 | " -f '%%(title)s (%%(pubDate)s)\\n%%(description)s\\n%%(link)s'\n" 151 | " This will trigger the screensaver to fetch the contents from the CNN feed\n" 152 | " and display all contents as specified in the formatting.\n" 153 | msgstr "" 154 | 155 | #: termsaverlib/screen/base/rssfeed.py:248 156 | msgid "There was an error while using your format." 157 | msgstr "" 158 | 159 | #: termsaverlib/screen/base/filereader.py:154 160 | #, python-format 161 | msgid "" 162 | "\n" 163 | "Options:\n" 164 | "\n" 165 | " -p, --path Sets the location to search for text-based source files.\n" 166 | " this option is mandatory.\n" 167 | " -d, --delay Sets the speed of the displaying characters\n" 168 | " default is%(default_delay)s of a second\n" 169 | " -h, --help Displays this help message\n" 170 | "\n" 171 | "Examples:\n" 172 | "\n" 173 | " $ %(app_name)s %(screen)s -p /path/to/my/code\n" 174 | " This will trigger the screensaver to read all files in the path selected\n" 175 | "\n" 176 | " $ %(app_name)s %(screen)s -p /path/to/my/code -d 0\n" 177 | " This will trigger the screensaver to read all files in the path selected\n" 178 | " with no delay (too fast for a screensaver, but it's your choice that\n" 179 | " matters!)\n" 180 | msgstr "" 181 | 182 | #: termsaverlib/screen/base/filereader.py:206 183 | msgid "Make sure the file or directory exists." 184 | msgstr "" 185 | 186 | #: termsaverlib/screen/base/filereader.py:214 187 | #: termsaverlib/screen/base/urlfetcher.py:184 188 | msgid "It is mandatory option" 189 | msgstr "" 190 | 191 | #: termsaverlib/screen/base/urlfetcher.py:122 192 | #, python-format 193 | msgid "" 194 | "\n" 195 | "Options:\n" 196 | "\n" 197 | " -u, --url Defines the URL location from where the information\n" 198 | " should be fetched, then displayed.\n" 199 | " This option is MANDATORY.\n" 200 | " -d, --delay Sets the speed of the displaying characters\n" 201 | " default is 0.003 of a second (advised to keep\n" 202 | " between 0.01 and 0.001).\n" 203 | " -h, --help Displays this help message\n" 204 | "\n" 205 | "Examples:\n" 206 | "\n" 207 | " $ %(app_name)s %(screen)s -u www.google.com\n" 208 | " This will trigger the screensaver to fetch the HTML contents of this web\n" 209 | " site and display progressively.\n" 210 | "\n" 211 | " $ %(app_name)s %(screen)s -u www.google.com -d 0\n" 212 | " This will trigger the screensaver to fetch the HTML contents of this web\n" 213 | " site with no delay (too fast for a screensaver, but it's your choice that\n" 214 | " matters!)\n" 215 | msgstr "" 216 | 217 | #: termsaverlib/screen/dot.py:69 218 | msgid "displays a random running dot" 219 | msgstr "" 220 | 221 | #: termsaverlib/screen/dot.py:120 222 | #, python-format 223 | msgid "" 224 | "\n" 225 | "Options:\n" 226 | "\n" 227 | " -c, --char Sets the character to be showing up\n" 228 | " default is X\n" 229 | " -d, --delay Sets the speed of the displaying characters\n" 230 | " default is 0.05 of a second (advised to keep\n" 231 | " between 0.1 and 0.01).\n" 232 | " -h, --help Displays this help message\n" 233 | "\n" 234 | "Example:\n" 235 | "\n" 236 | " $ %(app_name)s %(screen)s\n" 237 | " This will trigger the screensaver to display a dot on screen, with random\n" 238 | " size increase.\n" 239 | "\n" 240 | " $ %(app_name)s %(screen)s -c +\n" 241 | " Overrides the default dot (.) character to be a plus sign (+)\n" 242 | "\n" 243 | msgstr "" 244 | 245 | #: termsaverlib/screen/rfc.py:99 246 | msgid "randomly displays RFC contents" 247 | msgstr "" 248 | 249 | #: termsaverlib/screen/programmer.py:69 250 | msgid "displays source code in typing animation" 251 | msgstr "" 252 | 253 | #: termsaverlib/screen/programmer.py:78 254 | #, python-format 255 | msgid "" 256 | "\n" 257 | "You just need to provide the path to the location from where %(app_title)s will\n" 258 | "read and display on screen.\n" 259 | "\n" 260 | "If you do not have any code in your local machine, just get some interesting\n" 261 | "project from the Internet, such as Django (http://www.djangoproject.com):\n" 262 | "\n" 263 | " If you have access to subversion, you may download it at:\n" 264 | " svn co https://code.djangoproject.com/svn/django/trunk/ django-trunk\n" 265 | "\n" 266 | " Or, just download the zipped source and unpack it on your local machine:\n" 267 | " https://www.djangoproject.com/download/\n" 268 | msgstr "" 269 | 270 | #: termsaverlib/screen/urlfetcher.py:56 271 | msgid "displays url contents with typing animation" 272 | msgstr "" 273 | 274 | #: termsaverlib/screen/urlfetcher.py:61 275 | #, python-format 276 | msgid "" 277 | "\n" 278 | "You just need to provide the URL from where %(app_title)s will read and\n" 279 | "display on screen.\n" 280 | "\n" 281 | "If you do not have any idea which URL to use, check out some examples here:\n" 282 | "\n" 283 | " RFC\n" 284 | " RFC-1034 - http://tools.ietf.org/rfc/rfc1034.txt\n" 285 | "\n" 286 | " See a RFC list from Wikipedia:\n" 287 | " http://en.wikipedia.org/wiki/List_of_RFCs\n" 288 | " (remember to use the txt version)\n" 289 | "\n" 290 | msgstr "" 291 | 292 | #: termsaverlib/screen/jokes4all.py:83 293 | msgid "displays recent jokes from jokes4all.net (NSFW)" 294 | msgstr "" 295 | --------------------------------------------------------------------------------