├── .gitattributes ├── .gitignore ├── .replit ├── 51read.py ├── LICENSE ├── Pipfile ├── Pipfile.lock ├── Procfile ├── README.md ├── app ├── __init__.py ├── auth │ ├── __init__.py │ ├── forms.py │ └── routes.py ├── errors │ ├── __init__.py │ └── routes.py ├── main │ ├── __init__.py │ ├── forms.py │ └── routes.py ├── models │ ├── books.py │ └── users.py ├── static │ ├── css │ │ ├── fonts │ │ │ ├── GrandHotel-Regular.ttf │ │ │ ├── fontello.eot │ │ │ ├── fontello.svg │ │ │ ├── fontello.ttf │ │ │ ├── fontello.woff │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ ├── images │ │ │ ├── annotation-check.svg │ │ │ ├── annotation-comment.svg │ │ │ ├── annotation-help.svg │ │ │ ├── annotation-insert.svg │ │ │ ├── annotation-key.svg │ │ │ ├── annotation-newparagraph.svg │ │ │ ├── annotation-noicon.svg │ │ │ ├── annotation-note.svg │ │ │ ├── annotation-paragraph.svg │ │ │ ├── findbarButton-next-rtl.png │ │ │ ├── findbarButton-next-rtl@2x.png │ │ │ ├── findbarButton-next.png │ │ │ ├── findbarButton-next@2x.png │ │ │ ├── findbarButton-previous-rtl.png │ │ │ ├── findbarButton-previous-rtl@2x.png │ │ │ ├── findbarButton-previous.png │ │ │ ├── findbarButton-previous@2x.png │ │ │ ├── grab.cur │ │ │ ├── grabbing.cur │ │ │ ├── loading-icon.gif │ │ │ ├── loading-small.png │ │ │ ├── loading-small@2x.png │ │ │ ├── secondaryToolbarButton-documentProperties.png │ │ │ ├── secondaryToolbarButton-documentProperties@2x.png │ │ │ ├── secondaryToolbarButton-firstPage.png │ │ │ ├── secondaryToolbarButton-firstPage@2x.png │ │ │ ├── secondaryToolbarButton-handTool.png │ │ │ ├── secondaryToolbarButton-handTool@2x.png │ │ │ ├── secondaryToolbarButton-lastPage.png │ │ │ ├── secondaryToolbarButton-lastPage@2x.png │ │ │ ├── secondaryToolbarButton-rotateCcw.png │ │ │ ├── secondaryToolbarButton-rotateCcw@2x.png │ │ │ ├── secondaryToolbarButton-rotateCw.png │ │ │ ├── secondaryToolbarButton-rotateCw@2x.png │ │ │ ├── shadow.png │ │ │ ├── texture.png │ │ │ ├── toolbarButton-bookmark.png │ │ │ ├── toolbarButton-bookmark@2x.png │ │ │ ├── toolbarButton-cancle.png │ │ │ ├── toolbarButton-cancle@2x.png │ │ │ ├── toolbarButton-download.png │ │ │ ├── toolbarButton-download@2x.png │ │ │ ├── toolbarButton-menuArrows.png │ │ │ ├── toolbarButton-menuArrows@2x.png │ │ │ ├── toolbarButton-openFile.png │ │ │ ├── toolbarButton-openFile@2x.png │ │ │ ├── toolbarButton-pageDown-rtl.png │ │ │ ├── toolbarButton-pageDown-rtl@2x.png │ │ │ ├── toolbarButton-pageDown.png │ │ │ ├── toolbarButton-pageDown@2x.png │ │ │ ├── toolbarButton-pageUp-rtl.png │ │ │ ├── toolbarButton-pageUp-rtl@2x.png │ │ │ ├── toolbarButton-pageUp.png │ │ │ ├── toolbarButton-pageUp@2x.png │ │ │ ├── toolbarButton-presentationMode.png │ │ │ ├── toolbarButton-presentationMode@2x.png │ │ │ ├── toolbarButton-print.png │ │ │ ├── toolbarButton-print@2x.png │ │ │ ├── toolbarButton-search.png │ │ │ ├── toolbarButton-search@2x.png │ │ │ ├── toolbarButton-secondaryToolbarToggle-rtl.png │ │ │ ├── toolbarButton-secondaryToolbarToggle-rtl@2x.png │ │ │ ├── toolbarButton-secondaryToolbarToggle.png │ │ │ ├── toolbarButton-secondaryToolbarToggle@2x.png │ │ │ ├── toolbarButton-sidebarToggle-rtl.png │ │ │ ├── toolbarButton-sidebarToggle-rtl@2x.png │ │ │ ├── toolbarButton-sidebarToggle.png │ │ │ ├── toolbarButton-sidebarToggle@2x.png │ │ │ ├── toolbarButton-viewAttachments.png │ │ │ ├── toolbarButton-viewAttachments@2x.png │ │ │ ├── toolbarButton-viewOutline-rtl.png │ │ │ ├── toolbarButton-viewOutline-rtl@2x.png │ │ │ ├── toolbarButton-viewOutline.png │ │ │ ├── toolbarButton-viewOutline@2x.png │ │ │ ├── toolbarButton-viewThumbnail.png │ │ │ ├── toolbarButton-viewThumbnail@2x.png │ │ │ ├── toolbarButton-zoomIn.png │ │ │ ├── toolbarButton-zoomIn@2x.png │ │ │ ├── toolbarButton-zoomOut.png │ │ │ ├── toolbarButton-zoomOut@2x.png │ │ │ ├── treeitem-collapsed-rtl.png │ │ │ ├── treeitem-collapsed-rtl@2x.png │ │ │ ├── treeitem-collapsed.png │ │ │ ├── treeitem-collapsed@2x.png │ │ │ ├── treeitem-expanded.png │ │ │ └── treeitem-expanded@2x.png │ │ ├── kthoom.css │ │ ├── libs │ │ │ ├── bootstrap.min.css │ │ │ ├── normalize.css │ │ │ └── viewer.css │ │ ├── main.css │ │ ├── popup.css │ │ └── styles.css │ ├── favicon.ico │ ├── generic_cover.jpg │ ├── img │ │ ├── annotator-glyph-sprite.png │ │ ├── annotator-icon-sprite.png │ │ ├── apple-touch-icon.png │ │ ├── cancelfullscreen.png │ │ ├── close.png │ │ ├── fullscreen.png │ │ ├── goodreads.svg │ │ ├── loader.gif │ │ ├── menu-icon.png │ │ ├── save.png │ │ ├── saved.png │ │ ├── settings-s.png │ │ ├── settings.png │ │ └── star.png │ ├── js │ │ ├── archive.js │ │ ├── io.js │ │ ├── kthoom.js │ │ ├── libs │ │ │ ├── bootstrap.min.js │ │ │ ├── compatibility.js │ │ │ ├── epub.js │ │ │ ├── epub.min.js │ │ │ ├── epub.min.map │ │ │ ├── hooks.min.js │ │ │ ├── jquery.min.js │ │ │ ├── jszip.min.js │ │ │ ├── l10n.js │ │ │ ├── localforage.min.js │ │ │ ├── pdf.js │ │ │ ├── pdf.worker.js │ │ │ ├── reader.min.js │ │ │ ├── screenfull.min.js │ │ │ ├── viewer.js │ │ │ └── zip.min.js │ │ ├── reader.js │ │ ├── reader.js.map │ │ ├── reader.min.js │ │ ├── reader.min.map │ │ ├── unrar.js │ │ ├── untar.js │ │ └── unzip.js │ └── locale │ │ ├── ach │ │ └── viewer.properties │ │ ├── af │ │ └── viewer.properties │ │ ├── ak │ │ └── viewer.properties │ │ ├── an │ │ └── viewer.properties │ │ ├── ar │ │ └── viewer.properties │ │ ├── as │ │ └── viewer.properties │ │ ├── ast │ │ └── viewer.properties │ │ ├── az │ │ └── viewer.properties │ │ ├── be │ │ └── viewer.properties │ │ ├── bg │ │ └── viewer.properties │ │ ├── bn-BD │ │ └── viewer.properties │ │ ├── bn-IN │ │ └── viewer.properties │ │ ├── br │ │ └── viewer.properties │ │ ├── bs │ │ └── viewer.properties │ │ ├── ca │ │ └── viewer.properties │ │ ├── cs │ │ └── viewer.properties │ │ ├── csb │ │ └── viewer.properties │ │ ├── cy │ │ └── viewer.properties │ │ ├── da │ │ └── viewer.properties │ │ ├── de │ │ └── viewer.properties │ │ ├── el │ │ └── viewer.properties │ │ ├── en-GB │ │ └── viewer.properties │ │ ├── en-US │ │ └── viewer.properties │ │ ├── en-ZA │ │ └── viewer.properties │ │ ├── eo │ │ └── viewer.properties │ │ ├── es-AR │ │ └── viewer.properties │ │ ├── es-CL │ │ └── viewer.properties │ │ ├── es-ES │ │ └── viewer.properties │ │ ├── es-MX │ │ └── viewer.properties │ │ ├── et │ │ └── viewer.properties │ │ ├── eu │ │ └── viewer.properties │ │ ├── fa │ │ └── viewer.properties │ │ ├── ff │ │ └── viewer.properties │ │ ├── fi │ │ └── viewer.properties │ │ ├── fr │ │ └── viewer.properties │ │ ├── fy-NL │ │ └── viewer.properties │ │ ├── ga-IE │ │ └── viewer.properties │ │ ├── gd │ │ └── viewer.properties │ │ ├── gl │ │ └── viewer.properties │ │ ├── gu-IN │ │ └── viewer.properties │ │ ├── he │ │ └── viewer.properties │ │ ├── hi-IN │ │ └── viewer.properties │ │ ├── hr │ │ └── viewer.properties │ │ ├── hu │ │ └── viewer.properties │ │ ├── hy-AM │ │ └── viewer.properties │ │ ├── id │ │ └── viewer.properties │ │ ├── is │ │ └── viewer.properties │ │ ├── it │ │ └── viewer.properties │ │ ├── ja │ │ └── viewer.properties │ │ ├── ka │ │ └── viewer.properties │ │ ├── kk │ │ └── viewer.properties │ │ ├── km │ │ └── viewer.properties │ │ ├── kn │ │ └── viewer.properties │ │ ├── ko │ │ └── viewer.properties │ │ ├── ku │ │ └── viewer.properties │ │ ├── lg │ │ └── viewer.properties │ │ ├── lij │ │ └── viewer.properties │ │ ├── locale.properties │ │ ├── lt │ │ └── viewer.properties │ │ ├── lv │ │ └── viewer.properties │ │ ├── mai │ │ └── viewer.properties │ │ ├── mk │ │ └── viewer.properties │ │ ├── ml │ │ └── viewer.properties │ │ ├── mn │ │ └── viewer.properties │ │ ├── mr │ │ └── viewer.properties │ │ ├── ms │ │ └── viewer.properties │ │ ├── my │ │ └── viewer.properties │ │ ├── nb-NO │ │ └── viewer.properties │ │ ├── nl │ │ └── viewer.properties │ │ ├── nn-NO │ │ └── viewer.properties │ │ ├── nso │ │ └── viewer.properties │ │ ├── oc │ │ └── viewer.properties │ │ ├── or │ │ └── viewer.properties │ │ ├── pa-IN │ │ └── viewer.properties │ │ ├── pl │ │ └── viewer.properties │ │ ├── pt-BR │ │ └── viewer.properties │ │ ├── pt-PT │ │ └── viewer.properties │ │ ├── rm │ │ └── viewer.properties │ │ ├── ro │ │ └── viewer.properties │ │ ├── ru │ │ └── viewer.properties │ │ ├── rw │ │ └── viewer.properties │ │ ├── sah │ │ └── viewer.properties │ │ ├── si │ │ └── viewer.properties │ │ ├── sk │ │ └── viewer.properties │ │ ├── sl │ │ └── viewer.properties │ │ ├── son │ │ └── viewer.properties │ │ ├── sq │ │ └── viewer.properties │ │ ├── sr │ │ └── viewer.properties │ │ ├── sv-SE │ │ └── viewer.properties │ │ ├── sw │ │ └── viewer.properties │ │ ├── ta-LK │ │ └── viewer.properties │ │ ├── ta │ │ └── viewer.properties │ │ ├── te │ │ └── viewer.properties │ │ ├── th │ │ └── viewer.properties │ │ ├── tl │ │ └── viewer.properties │ │ ├── tn │ │ └── viewer.properties │ │ ├── tr │ │ └── viewer.properties │ │ ├── uk │ │ └── viewer.properties │ │ ├── ur │ │ └── viewer.properties │ │ ├── vi │ │ └── viewer.properties │ │ ├── wo │ │ └── viewer.properties │ │ ├── xh │ │ └── viewer.properties │ │ ├── zh-CN │ │ └── viewer.properties │ │ ├── zh-TW │ │ └── viewer.properties │ │ └── zu │ │ └── viewer.properties ├── templates │ ├── auth │ │ ├── change_kindle_mail.html │ │ ├── change_password.html │ │ ├── login.html │ │ ├── register.html │ │ ├── reset_password.html │ │ ├── reset_password_request.html │ │ └── unconfirmed.html │ ├── base.html │ ├── email │ │ ├── confirm.html │ │ ├── confirm.txt │ │ ├── reset_password.html │ │ └── reset_password.txt │ ├── errors │ │ ├── 403.html │ │ ├── 404.html │ │ └── 500.html │ └── main │ │ ├── convert_book.html │ │ ├── index.html │ │ ├── readepub.html │ │ ├── readpdf.html │ │ └── readtxt.html └── utils │ ├── __init__.py │ ├── book_format.py │ ├── book_meta.py │ ├── email.py │ ├── epub.py │ ├── fb2.py │ ├── helper.py │ ├── pdf.py │ └── qiniuutils.py ├── config.py ├── migrations ├── README ├── alembic.ini ├── env.py ├── script.py.mako └── versions │ ├── 0af7310c8a58_books_table.py │ └── 9324a63ac6e1_users_table.py ├── runtime.txt └── tests ├── test_basics.py └── test_user_model.py /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=python 2 | *.css linguist-language=python 3 | *.html linguist-language=python 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /.replit: -------------------------------------------------------------------------------- 1 | language = "python3" 2 | run = "flask db upgrade;gunicorn 51read:app" 3 | -------------------------------------------------------------------------------- /51read.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/6/7 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import os 6 | import sys 7 | 8 | import click 9 | 10 | from app import create_app, db 11 | from app.models.books import Books 12 | 13 | COV = None 14 | if os.environ.get('FLASK_COVERAGE'): 15 | import coverage 16 | COV = coverage.coverage(branch=True, include='app/*') 17 | COV.start() 18 | 19 | app = create_app() 20 | 21 | 22 | @app.shell_context_processor 23 | def make_shell_context(): 24 | return dict(db=db, Books=Books) 25 | 26 | 27 | @app.cli.command() 28 | @click.option('--coverage/--no-coverage', default=False, 29 | help='Run tests under code coverage.') 30 | def test(coverage): 31 | """Run the unit tests.""" 32 | if coverage and not os.environ.get('FLASK_COVERAGE'): 33 | import subprocess 34 | os.environ['FLASK_COVERAGE'] = '1' 35 | sys.exit(subprocess.call(sys.argv)) 36 | 37 | import unittest 38 | tests = unittest.TestLoader().discover('tests') 39 | unittest.TextTestRunner(verbosity=2).run(tests) 40 | if COV: 41 | COV.stop() 42 | COV.save() 43 | print('Coverage Summary:') 44 | COV.report() 45 | basedir = os.path.abspath(os.path.dirname(__file__)) 46 | covdir = os.path.join(basedir, 'tests/coverage') 47 | COV.html_report(directory=covdir) 48 | print('HTML version: file://%s/index.html' % covdir) 49 | COV.erase() 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 geekspeng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.doubanio.com/simple/" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | flask = "*" 8 | flask-sqlalchemy = "*" 9 | flask-login = "*" 10 | flask-bootstrap = "*" 11 | flask-migrate = "*" 12 | flask-mail = "*" 13 | flask-babel = "*" 14 | flask-wtf = "*" 15 | flask-moment = "*" 16 | redis = "*" 17 | rq = "*" 18 | coverage = "*" 19 | pyjwt = "*" 20 | python-dotenv = "*" 21 | flask-uploads = "*" 22 | "pypdf2" = "*" 23 | lxml = "*" 24 | "iso-639" = "*" 25 | gunicorn = "*" 26 | "psycopg2" = "*" 27 | qiniu = "*" 28 | 29 | [dev-packages] 30 | 31 | [requires] 32 | python_version = "3.6.6" 33 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: flask db upgrade; flask test --coverage; gunicorn 51read:app 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 51-read 2 | 51-read是一款Web应用,无需下载和安装即可使用。它可以管理、阅读、转换、搜索和下载电子书。 3 | 4 | # 特性 5 | 1. 支持上传以及删除电子书(.fb2,.epub,.pdf) 6 | 2. 支持直接在浏览器中阅读电子书(.txt,.epub,.pdf,.cbr,.cbt,.cbz) 7 | 3. 支持将电子书从EPUB转换为Kindle格式(mobi / azw) 8 | 4. 支持一键发送电子书到Kindle设备 9 | 5. 本地搜索 10 | 6. 支持在线下载电子书 11 | 7. 多语言支持(简体中文,英语) 12 | 8. 用户认证 13 | 9. 用户管理 14 | 10. 用户权限管理 15 | 11. 将电子书下载限制为登录用户 16 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/8/29 17:52 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import os 6 | import logging 7 | from logging.handlers import SMTPHandler, RotatingFileHandler 8 | from flask import Flask 9 | from flask_bootstrap import Bootstrap 10 | from flask_mail import Mail 11 | from flask_sqlalchemy import SQLAlchemy 12 | from flask_migrate import Migrate 13 | from flask_uploads import UploadSet, configure_uploads, patch_request_class 14 | from config import Config 15 | from flask_login import LoginManager 16 | 17 | bootstrap = Bootstrap() 18 | db = SQLAlchemy() 19 | migrate = Migrate() 20 | mail = Mail() 21 | login_manager = LoginManager() 22 | login_manager.login_view = 'auth.login' 23 | login_manager.login_message = 'Please log in to access this page.' 24 | 25 | uploads = UploadSet('uploads', ('txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'cbt', 'doc', 'docx', 'fb2')) 26 | 27 | 28 | def create_app(config_class=Config): 29 | app = Flask(__name__) 30 | app.config.from_object(config_class) 31 | 32 | bootstrap.init_app(app) 33 | mail.init_app(app) 34 | db.init_app(app) 35 | migrate.init_app(app, db) 36 | login_manager.init_app(app) 37 | 38 | configure_uploads(app, uploads) 39 | patch_request_class(app) 40 | 41 | from app.errors import errors as errors_blueprint 42 | app.register_blueprint(errors_blueprint) 43 | 44 | from app.auth import auth as auth_blueprint 45 | app.register_blueprint(auth_blueprint, url_prefix='/auth') 46 | 47 | from app.main import main as main_blueprint 48 | app.register_blueprint(main_blueprint) 49 | 50 | if not app.debug and not app.testing: 51 | if app.config['MAIL_SERVER']: 52 | auth = None 53 | if app.config['MAIL_USERNAME'] and app.config['MAIL_PASSWORD']: 54 | auth = (app.config['MAIL_USERNAME'], 55 | app.config['MAIL_PASSWORD']) 56 | secure = None 57 | if app.config['MAIL_USE_TLS']: 58 | secure = () 59 | mail_handler = SMTPHandler( 60 | mailhost=(app.config['MAIL_SERVER'], app.config['MAIL_PORT']), 61 | fromaddr='no-reply@' + app.config['MAIL_SERVER'], 62 | toaddrs=app.config['ADMIN'], subject='51read Failure', 63 | credentials=auth, secure=secure) 64 | mail_handler.setLevel(logging.ERROR) 65 | app.logger.addHandler(mail_handler) 66 | 67 | if app.config['LOG_TO_STDOUT']: 68 | stream_handler = logging.StreamHandler() 69 | stream_handler.setLevel(logging.INFO) 70 | app.logger.addHandler(stream_handler) 71 | else: 72 | if not os.path.exists('logs'): 73 | os.mkdir('logs') 74 | file_handler = RotatingFileHandler('logs/51read.log', 75 | maxBytes=10240, backupCount=10) 76 | file_handler.setFormatter(logging.Formatter( 77 | '%(asctime)s %(levelname)s: %(message)s ' 78 | '[in %(pathname)s:%(lineno)d]')) 79 | file_handler.setLevel(logging.INFO) 80 | app.logger.addHandler(file_handler) 81 | 82 | app.logger.setLevel(logging.INFO) 83 | app.logger.info('51read startup') 84 | 85 | return app 86 | -------------------------------------------------------------------------------- /app/auth/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/6/7 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | from flask import Blueprint 6 | 7 | auth = Blueprint('auth', __name__) 8 | 9 | from . import routes 10 | -------------------------------------------------------------------------------- /app/auth/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/8/29 17:52 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | from flask_wtf import FlaskForm 6 | from wtforms import StringField, PasswordField, BooleanField, SubmitField 7 | from wtforms.validators import DataRequired, Email, EqualTo, Length, ValidationError 8 | from app.models.users import Users 9 | 10 | 11 | class LoginForm(FlaskForm): 12 | email = StringField('Email', validators=[DataRequired(), Email()]) 13 | password = PasswordField('Password', validators=[DataRequired()]) 14 | remember_me = BooleanField('Remember Me') 15 | submit = SubmitField('Sign In') 16 | 17 | 18 | class RegistrationForm(FlaskForm): 19 | email = StringField('Email', validators=[DataRequired(), Email()]) 20 | password = PasswordField('Password', validators=[DataRequired(), Length(6, 24)]) 21 | password2 = PasswordField('Confirm Password', validators=[DataRequired(), Length(6, 24), EqualTo('password')]) 22 | # recaptcha = RecaptchaField() 23 | submit = SubmitField('Register') 24 | 25 | def validate_email(self, email): 26 | user = Users.query.filter_by(email=email.data).first() 27 | if user is not None: 28 | raise ValidationError('The email is registered, please use a different email address.') 29 | 30 | 31 | class ChangePasswordForm(FlaskForm): 32 | old_password = PasswordField('Old password', validators=[DataRequired(), Length(6, 24)]) 33 | password = PasswordField('New Password', validators=[DataRequired(), Length(6, 24)]) 34 | password2 = PasswordField('Confirm new password', validators=[DataRequired(), Length(6, 24), EqualTo('password')]) 35 | submit = SubmitField('Update Password') 36 | 37 | 38 | class ChangeKindleEmailForm(FlaskForm): 39 | kindle_email = StringField('Email', validators=[DataRequired(), Email()]) 40 | submit = SubmitField('Update Kindle Email') 41 | 42 | 43 | class ResetPasswordRequestForm(FlaskForm): 44 | email = StringField('Email', validators=[DataRequired(), Email()]) 45 | # recaptcha = RecaptchaField() 46 | submit = SubmitField('Confirm') 47 | 48 | def validate_email(self, email): 49 | user = Users.query.filter_by(email=email.data).first() 50 | if user is None: 51 | raise ValidationError('The email is not registered, please use a different email address.') 52 | 53 | 54 | class ResetPasswordForm(FlaskForm): 55 | password = PasswordField('Password', validators=[DataRequired()]) 56 | password2 = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')]) 57 | submit = SubmitField('Reset Password') -------------------------------------------------------------------------------- /app/errors/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/6/7 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | from flask import Blueprint 6 | 7 | errors = Blueprint('errors', __name__) 8 | 9 | from . import routes 10 | -------------------------------------------------------------------------------- /app/errors/routes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/8/29 18:00 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | from flask import render_template 6 | from . import errors 7 | 8 | 9 | @errors.app_errorhandler(403) 10 | def forbidden(e): 11 | return render_template('errors/403.html'), 403 12 | 13 | 14 | @errors.app_errorhandler(404) 15 | def page_not_found(e): 16 | return render_template('errors/404.html'), 404 17 | 18 | 19 | @errors.app_errorhandler(500) 20 | def internal_server_error(e): 21 | return render_template('errors/500.html'), 500 22 | -------------------------------------------------------------------------------- /app/main/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/6/7 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | from flask import Blueprint 6 | 7 | main = Blueprint('main', __name__) 8 | 9 | from . import routes 10 | -------------------------------------------------------------------------------- /app/main/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/8/29 17:52 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | from flask_wtf import FlaskForm 6 | from wtforms import SelectField, SubmitField 7 | from wtforms.validators import DataRequired, ValidationError 8 | 9 | 10 | class ConvertBookForm(FlaskForm): 11 | convert_from = SelectField('Convert from', validators=[DataRequired()], coerce=str) 12 | convert_to = SelectField('Convert to', validators=[DataRequired()], coerce=str) 13 | submit = SubmitField('Convert Book') 14 | 15 | def __init__(self, book, *args, **kwargs): 16 | super(ConvertBookForm, self).__init__(*args, **kwargs) 17 | self.convert_from.choices = [(data.format.lower(), data.format.lower()) for data in book.data] 18 | self.convert_to.choices = [('azw3', 'azw3'), ('mobi', 'mobi'), ('epub', 'epub'), ('fb2', 'fb2'), ('pdf', 'pdf'), 19 | ('docx', 'docx'), ('txt', 'txt')] 20 | 21 | def validate_convert_to(self, field): 22 | if self.convert_from.data == field.data: 23 | raise ValidationError('Book format cannot be the same') 24 | -------------------------------------------------------------------------------- /app/models/users.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/8/30 15:50 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | from datetime import datetime 6 | from hashlib import md5 7 | from time import time 8 | 9 | import jwt 10 | from flask import current_app 11 | from flask_login import UserMixin 12 | from werkzeug.security import generate_password_hash, check_password_hash 13 | 14 | from app import db, login_manager 15 | 16 | 17 | class Users(UserMixin, db.Model): 18 | id = db.Column(db.Integer, primary_key=True) 19 | email = db.Column(db.String(120), index=True, unique=True) 20 | kindle_email = db.Column(db.String(120), default="") 21 | password_hash = db.Column(db.String(128)) 22 | member_since = db.Column(db.DateTime(), default=datetime.utcnow) 23 | last_seen = db.Column(db.DateTime(), default=datetime.utcnow) 24 | confirmed = db.Column(db.Boolean(), default=False) 25 | 26 | def __repr__(self): 27 | return '' % self.email 28 | 29 | def set_password(self, password): 30 | self.password_hash = generate_password_hash(password) 31 | 32 | def check_password(self, password): 33 | return check_password_hash(self.password_hash, password) 34 | 35 | def avatar(self, size=20): 36 | digest = md5(self.email.lower().encode('utf-8')).hexdigest() 37 | return 'https://www.gravatar.com/avatar/{}?d=identicon&s={}'.format( 38 | digest, size) 39 | 40 | def ping(self): 41 | self.last_seen = datetime.utcnow() 42 | db.session.add(self) 43 | db.session.commit() 44 | 45 | def generate_confirmation_token(self, expires_in=600): 46 | return jwt.encode( 47 | {'confirmation': self.id, 'exp': time() + expires_in}, 48 | current_app.config['SECRET_KEY'], 49 | algorithm='HS256').decode('utf-8') 50 | 51 | @staticmethod 52 | def check_confirmation_token(token): 53 | try: 54 | id = jwt.decode(token, current_app.config['SECRET_KEY'], 55 | algorithms=['HS256'])['confirmation'] 56 | except Exception: 57 | return None 58 | return Users.query.get(id) 59 | 60 | def generate_reset_password_token(self, expires_in=600): 61 | return jwt.encode( 62 | {'reset_password': self.id, 'exp': time() + expires_in}, 63 | current_app.config['SECRET_KEY'], 64 | algorithm='HS256').decode('utf-8') 65 | 66 | @staticmethod 67 | def check_reset_password_token(token): 68 | try: 69 | id = jwt.decode(token, current_app.config['SECRET_KEY'], 70 | algorithms=['HS256'])['reset_password'] 71 | except: 72 | return None 73 | return Users.query.get(id) 74 | 75 | 76 | @login_manager.user_loader 77 | def load_user(id): 78 | return Users.query.get(int(id)) 79 | -------------------------------------------------------------------------------- /app/static/css/fonts/GrandHotel-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/fonts/GrandHotel-Regular.ttf -------------------------------------------------------------------------------- /app/static/css/fonts/fontello.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/fonts/fontello.eot -------------------------------------------------------------------------------- /app/static/css/fonts/fontello.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/fonts/fontello.ttf -------------------------------------------------------------------------------- /app/static/css/fonts/fontello.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/fonts/fontello.woff -------------------------------------------------------------------------------- /app/static/css/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /app/static/css/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /app/static/css/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /app/static/css/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /app/static/css/images/annotation-check.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/static/css/images/annotation-comment.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /app/static/css/images/annotation-help.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 16 | 18 | 21 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/static/css/images/annotation-insert.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/static/css/images/annotation-key.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/static/css/images/annotation-newparagraph.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/static/css/images/annotation-noicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/static/css/images/annotation-note.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 14 | 21 | 28 | 35 | 42 | 43 | -------------------------------------------------------------------------------- /app/static/css/images/annotation-paragraph.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /app/static/css/images/findbarButton-next-rtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/findbarButton-next-rtl.png -------------------------------------------------------------------------------- /app/static/css/images/findbarButton-next-rtl@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/findbarButton-next-rtl@2x.png -------------------------------------------------------------------------------- /app/static/css/images/findbarButton-next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/findbarButton-next.png -------------------------------------------------------------------------------- /app/static/css/images/findbarButton-next@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/findbarButton-next@2x.png -------------------------------------------------------------------------------- /app/static/css/images/findbarButton-previous-rtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/findbarButton-previous-rtl.png -------------------------------------------------------------------------------- /app/static/css/images/findbarButton-previous-rtl@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/findbarButton-previous-rtl@2x.png -------------------------------------------------------------------------------- /app/static/css/images/findbarButton-previous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/findbarButton-previous.png -------------------------------------------------------------------------------- /app/static/css/images/findbarButton-previous@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/findbarButton-previous@2x.png -------------------------------------------------------------------------------- /app/static/css/images/grab.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/grab.cur -------------------------------------------------------------------------------- /app/static/css/images/grabbing.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/grabbing.cur -------------------------------------------------------------------------------- /app/static/css/images/loading-icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/loading-icon.gif -------------------------------------------------------------------------------- /app/static/css/images/loading-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/loading-small.png -------------------------------------------------------------------------------- /app/static/css/images/loading-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/loading-small@2x.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-documentProperties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-documentProperties.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-documentProperties@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-documentProperties@2x.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-firstPage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-firstPage.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-firstPage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-firstPage@2x.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-handTool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-handTool.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-handTool@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-handTool@2x.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-lastPage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-lastPage.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-lastPage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-lastPage@2x.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-rotateCcw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-rotateCcw.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-rotateCcw@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-rotateCcw@2x.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-rotateCw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-rotateCw.png -------------------------------------------------------------------------------- /app/static/css/images/secondaryToolbarButton-rotateCw@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/secondaryToolbarButton-rotateCw@2x.png -------------------------------------------------------------------------------- /app/static/css/images/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/shadow.png -------------------------------------------------------------------------------- /app/static/css/images/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/texture.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-bookmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-bookmark.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-bookmark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-bookmark@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-cancle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-cancle.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-cancle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-cancle@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-download.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-download@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-download@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-menuArrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-menuArrows.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-menuArrows@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-menuArrows@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-openFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-openFile.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-openFile@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-openFile@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-pageDown-rtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-pageDown-rtl.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-pageDown-rtl@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-pageDown-rtl@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-pageDown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-pageDown.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-pageDown@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-pageDown@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-pageUp-rtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-pageUp-rtl.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-pageUp-rtl@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-pageUp-rtl@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-pageUp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-pageUp.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-pageUp@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-pageUp@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-presentationMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-presentationMode.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-presentationMode@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-presentationMode@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-print.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-print@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-print@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-search.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-search@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-search@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-secondaryToolbarToggle-rtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-secondaryToolbarToggle-rtl.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-secondaryToolbarToggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-secondaryToolbarToggle.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-secondaryToolbarToggle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-secondaryToolbarToggle@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-sidebarToggle-rtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-sidebarToggle-rtl.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-sidebarToggle-rtl@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-sidebarToggle-rtl@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-sidebarToggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-sidebarToggle.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-sidebarToggle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-sidebarToggle@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-viewAttachments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-viewAttachments.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-viewAttachments@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-viewAttachments@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-viewOutline-rtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-viewOutline-rtl.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-viewOutline-rtl@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-viewOutline-rtl@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-viewOutline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-viewOutline.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-viewOutline@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-viewOutline@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-viewThumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-viewThumbnail.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-viewThumbnail@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-viewThumbnail@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-zoomIn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-zoomIn.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-zoomIn@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-zoomIn@2x.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-zoomOut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-zoomOut.png -------------------------------------------------------------------------------- /app/static/css/images/toolbarButton-zoomOut@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/toolbarButton-zoomOut@2x.png -------------------------------------------------------------------------------- /app/static/css/images/treeitem-collapsed-rtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/treeitem-collapsed-rtl.png -------------------------------------------------------------------------------- /app/static/css/images/treeitem-collapsed-rtl@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/treeitem-collapsed-rtl@2x.png -------------------------------------------------------------------------------- /app/static/css/images/treeitem-collapsed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/treeitem-collapsed.png -------------------------------------------------------------------------------- /app/static/css/images/treeitem-collapsed@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/treeitem-collapsed@2x.png -------------------------------------------------------------------------------- /app/static/css/images/treeitem-expanded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/treeitem-expanded.png -------------------------------------------------------------------------------- /app/static/css/images/treeitem-expanded@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/css/images/treeitem-expanded@2x.png -------------------------------------------------------------------------------- /app/static/css/kthoom.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #444; 3 | overflow: hidden; 4 | color: white; 5 | font-family: sans-serif; 6 | margin: 0px; 7 | } 8 | 9 | .main { 10 | position: re; 11 | left: 5px; 12 | overflow: hidden; 13 | right: 5px; 14 | text-align: center; 15 | top: 5px; 16 | } 17 | 18 | #progress { 19 | position: absolute; 20 | display: inline; 21 | left: 90px; 22 | right: 160px; 23 | height: 20px; 24 | margin-top: 1px; 25 | text-align: right; 26 | } 27 | 28 | .hide { 29 | display: none !important; 30 | } 31 | 32 | #mainText { 33 | text-align: left; 34 | width: 90%; 35 | position: relative; 36 | top: 10px; 37 | background: #ccc; 38 | color: black; 39 | margin-right: auto; 40 | margin-left: auto; 41 | padding: 10px; 42 | word-wrap: break-word; 43 | } 44 | 45 | #mainImage{ 46 | margin-top: 32px; 47 | } 48 | 49 | #titlebar.main { 50 | opacity: 0; 51 | position: absolute; 52 | top: 0; 53 | height: 30px; 54 | left: 0; 55 | right: 0; 56 | background-color: black; 57 | padding-bottom: 70px; 58 | -webkit-transition: opacity 0.2s ease; 59 | -moz-transition: opacity 0.2s ease; 60 | transition: opacity 0.2s ease; 61 | background: -moz-linear-gradient(top, rgba(0,2,34,1) 0%, rgba(0,1,24,1) 30%, rgba(0,0,0,0) 100%); /* FF3.6+ */ 62 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(0,2,34,1)), color-stop(30%,rgba(0,1,24,1)), color-stop(100%,rgba(0,0,0,0))); /* Chrome,Safari4+ */ 63 | background: -webkit-linear-gradient(top, rgba(0,2,34,1) 0%,rgba(0,1,24,1) 30%,rgba(0,0,0,0) 100%); /* Chrome10+,Safari5.1+ */ 64 | background: -o-linear-gradient(top, rgba(0,2,34,1) 0%,rgba(0,1,24,1) 30%,rgba(0,0,0,0) 100%); /* Opera11.10+ */ 65 | background: -ms-linear-gradient(top, rgba(0,2,34,1) 0%,rgba(0,1,24,1) 30%,rgba(0,0,0,0) 100%); /* IE10+ */ 66 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#000222', endColorstr='#00000000',GradientType=0 ); /* IE6-9 */ 67 | background: linear-gradient(top, rgba(0,2,34,1) 0%,rgba(0,1,24,1) 30%,rgba(0,0,0,0) 100%); /* W3C */ 68 | } 69 | 70 | #prev { 71 | left: 40px; 72 | } 73 | 74 | #next { 75 | right: 40px; 76 | } 77 | 78 | .arrow { 79 | position: absolute; 80 | top: 50%; 81 | margin-top: -32px; 82 | font-size: 64px; 83 | color: #E2E2E2; 84 | font-family: arial, sans-serif; 85 | font-weight: bold; 86 | cursor: pointer; 87 | -webkit-user-select: none; 88 | -khtml-user-select: none; 89 | -moz-user-select: none; 90 | -ms-user-select: none; 91 | user-select: none; 92 | } 93 | 94 | .arrow:hover { 95 | color: #777; 96 | } 97 | 98 | .arrow:active, 99 | .arrow.active { 100 | color: #000; 101 | } 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /app/static/css/popup.css: -------------------------------------------------------------------------------- 1 | /* http://davidwalsh.name/css-tooltips */ 2 | /* base CSS element */ 3 | .popup { 4 | background: #eee; 5 | border: 1px solid #ccc; 6 | padding: 10px; 7 | border-radius: 8px; 8 | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); 9 | position: fixed; 10 | max-width: 300px; 11 | font-size: 12px; 12 | 13 | display: none; 14 | margin-left: 2px; 15 | 16 | margin-top: 30px; 17 | } 18 | 19 | .popup.above { 20 | margin-top: -10px; 21 | } 22 | 23 | .popup.left { 24 | margin-left: -20px; 25 | } 26 | 27 | .popup.right { 28 | margin-left: 40px; 29 | } 30 | 31 | .pop_content { 32 | max-height: 225px; 33 | overflow-y: auto; 34 | } 35 | 36 | .pop_content > p { 37 | margin-top: 0; 38 | } 39 | 40 | /* below */ 41 | .popup:before { 42 | position: absolute; 43 | display: inline-block; 44 | border-bottom: 10px solid #eee; 45 | border-right: 10px solid transparent; 46 | border-left: 10px solid transparent; 47 | border-bottom-color: rgba(0, 0, 0, 0.2); 48 | left: 50%; 49 | top: -10px; 50 | margin-left: -6px; 51 | content: ''; 52 | } 53 | 54 | .popup:after { 55 | position: absolute; 56 | display: inline-block; 57 | border-bottom: 9px solid #eee; 58 | border-right: 9px solid transparent; 59 | border-left: 9px solid transparent; 60 | left: 50%; 61 | top: -9px; 62 | margin-left: -5px; 63 | content: ''; 64 | } 65 | 66 | /* above */ 67 | .popup.above:before { 68 | border-bottom: none; 69 | border-top: 10px solid #eee; 70 | border-top-color: rgba(0, 0, 0, 0.2); 71 | top: 100%; 72 | } 73 | 74 | .popup.above:after { 75 | border-bottom: none; 76 | border-top: 9px solid #eee; 77 | top: 100%; 78 | } 79 | 80 | .popup.left:before, 81 | .popup.left:after 82 | { 83 | left: 20px; 84 | } 85 | 86 | .popup.right:before, 87 | .popup.right:after 88 | { 89 | left: auto; 90 | right: 20px; 91 | } 92 | 93 | 94 | .popup.show, .popup.on { 95 | display: block; 96 | } -------------------------------------------------------------------------------- /app/static/css/styles.css: -------------------------------------------------------------------------------- 1 | #loader { 2 | position: absolute; 3 | z-index: 10; 4 | left: 50%; 5 | top: 50%; 6 | margin: -33px 0 0 -33px; 7 | } 8 | 9 | .container .book{margin-top:20px;height:320px;} 10 | .container .book .cover{height:225px;position:relative} 11 | .container .book .cover img{z-index:0;border:1px solid #fff;box-sizeing:border-box;height:100%;bottom:0;position:relative;-webkit-box-shadow: 0 5px 8px -6px #777;-moz-box-shadow: 0 5px 8px -6px #777;box-shadow: 0 5px 8px -6px #777;} 12 | .container .book .toolbar {z-index:100;position: absolute;bottom: 10px;left: 10px;text-decoration:none;} 13 | .container .book .delete {z-index:100;position: absolute;top: -5px;left: -5px;text-decoration:none;} 14 | .container .book .meta{margin-top:10px}.container .book .meta p{margin:0} 15 | .container .book .meta .title{font-weight:bold;font-size:15px;color:#444;} 16 | .container .book .meta .author{font-size:12px;color:#999} 17 | .container .book .meta .rating{margin-top:5px}.rating .glyphicon-star{color:#999}.rating .glyphicon-star.good{color:#45b29d} 18 | .book-meta {padding-bottom: 20px;} 19 | .book-meta .tags a {display: inline;} 20 | .book-meta .identifiers a {display: inline;} 21 | .container .single .cover img { 22 | border: 1px solid #fff; 23 | /*border-radius: 7px;*/ 24 | box-sizeing: border-box; 25 | -webkit-box-shadow: 0 5px 8px -6px #777; 26 | -moz-box-shadow: 0 5px 8px -6px #777; 27 | box-shadow: 0 5px 8px -6px #777; 28 | } 29 | 30 | .cover { margin-bottom: 10px;} 31 | 32 | .btn-file {position: relative; overflow: hidden;} 33 | .btn-file input[type=file] {position: absolute; top: 0; right: 0; min-width: 100%; min-height: 100%; font-size: 100px; text-align: right; filter: alpha(opacity=0); opacity: 0; outline: none; background: white; cursor: inherit; display: block;} -------------------------------------------------------------------------------- /app/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/favicon.ico -------------------------------------------------------------------------------- /app/static/generic_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/generic_cover.jpg -------------------------------------------------------------------------------- /app/static/img/annotator-glyph-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/annotator-glyph-sprite.png -------------------------------------------------------------------------------- /app/static/img/annotator-icon-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/annotator-icon-sprite.png -------------------------------------------------------------------------------- /app/static/img/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/apple-touch-icon.png -------------------------------------------------------------------------------- /app/static/img/cancelfullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/cancelfullscreen.png -------------------------------------------------------------------------------- /app/static/img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/close.png -------------------------------------------------------------------------------- /app/static/img/fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/fullscreen.png -------------------------------------------------------------------------------- /app/static/img/goodreads.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/static/img/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/loader.gif -------------------------------------------------------------------------------- /app/static/img/menu-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/menu-icon.png -------------------------------------------------------------------------------- /app/static/img/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/save.png -------------------------------------------------------------------------------- /app/static/img/saved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/saved.png -------------------------------------------------------------------------------- /app/static/img/settings-s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/settings-s.png -------------------------------------------------------------------------------- /app/static/img/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/settings.png -------------------------------------------------------------------------------- /app/static/img/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geekspeng/51-read/31d9697b50f57e66319870f403717f95a42cdc57/app/static/img/star.png -------------------------------------------------------------------------------- /app/static/js/libs/hooks.min.js: -------------------------------------------------------------------------------- 1 | EPUBJS.Hooks.register("beforeChapterDisplay").endnotes=function(a,b){var c=b.contents.querySelectorAll("a[href]"),d=Array.prototype.slice.call(c),e=EPUBJS.core.folder(location.pathname),f=(EPUBJS.cssPath,{});EPUBJS.core.addCss(EPUBJS.cssPath+"popup.css",!1,b.render.document.head),d.forEach(function(a){function c(){var c,h,n=b.height,o=b.width,p=225;m||(c=j.cloneNode(!0),m=c.querySelector("p")),f[i]||(f[i]=document.createElement("div"),f[i].setAttribute("class","popup"),pop_content=document.createElement("div"),f[i].appendChild(pop_content),pop_content.appendChild(m),pop_content.setAttribute("class","pop_content"),b.render.document.body.appendChild(f[i]),f[i].addEventListener("mouseover",d,!1),f[i].addEventListener("mouseout",e,!1),b.on("renderer:pageChanged",g,this),b.on("renderer:pageChanged",e,this)),c=f[i],h=a.getBoundingClientRect(),k=h.left,l=h.top,c.classList.add("show"),popRect=c.getBoundingClientRect(),c.style.left=k-popRect.width/2+"px",c.style.top=l+"px",p>n/2.5&&(p=n/2.5,pop_content.style.maxHeight=p+"px"),popRect.height+l>=n-25?(c.style.top=l-popRect.height+"px",c.classList.add("above")):c.classList.remove("above"),k-popRect.width<=0?(c.style.left=k+"px",c.classList.add("left")):c.classList.remove("left"),k+popRect.width/2>=o?(c.style.left=k-300+"px",popRect=c.getBoundingClientRect(),c.style.left=k-popRect.width+"px",popRect.height+l>=n-25?(c.style.top=l-popRect.height+"px",c.classList.add("above")):c.classList.remove("above"),c.classList.add("right")):c.classList.remove("right")}function d(){f[i].classList.add("on")}function e(){f[i].classList.remove("on")}function g(){setTimeout(function(){f[i].classList.remove("show")},100)}var h,i,j,k,l,m;"noteref"==a.getAttribute("epub:type")&&(h=a.getAttribute("href"),i=h.replace("#",""),j=b.render.document.getElementById(i),a.addEventListener("mouseover",c,!1),a.addEventListener("mouseout",g,!1))}),a&&a()},EPUBJS.Hooks.register("beforeChapterDisplay").mathml=function(a,b){if(b.currentChapter.manifestProperties.indexOf("mathml")!==-1){b.render.iframe.contentWindow.mathmlCallback=a;var c=document.createElement("script");c.type="text/x-mathjax-config",c.innerHTML=' MathJax.Hub.Register.StartupHook("End",function () { window.mathmlCallback(); }); MathJax.Hub.Config({jax: ["input/TeX","input/MathML","output/SVG"],extensions: ["tex2jax.js","mml2jax.js","MathEvents.js"],TeX: {extensions: ["noErrors.js","noUndefined.js","autoload-all.js"]},MathMenu: {showRenderer: false},menuSettings: {zoom: "Click"},messageStyle: "none"}); ',b.doc.body.appendChild(c),EPUBJS.core.addScript("http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML",null,b.doc.head)}else a&&a()},EPUBJS.Hooks.register("beforeChapterDisplay").smartimages=function(a,b){var c=b.contents.querySelectorAll("img"),d=Array.prototype.slice.call(c),e=b.height;if("reflowable"!=b.layoutSettings.layout)return void a();d.forEach(function(a){var c=function(){var c,d=a.getBoundingClientRect(),f=d.height,g=d.top,h=a.getAttribute("data-height"),i=h||f,j=Number(getComputedStyle(a,"").fontSize.match(/(\d*(\.\d*)?)px/)[1]),k=j?j/2:0;e=b.contents.clientHeight,g<0&&(g=0),i+g>=e?(ge&&(a.style.maxHeight=e+"px",a.style.width="auto",d=a.getBoundingClientRect(),i=d.height),a.style.display="block",a.style.WebkitColumnBreakBefore="always",a.style.breakBefore="column"),a.setAttribute("data-height",c)):(a.style.removeProperty("max-height"),a.style.removeProperty("margin-top"))},d=function(){b.off("renderer:resized",c),b.off("renderer:chapterUnload",this)};a.addEventListener("load",c,!1),b.on("renderer:resized",c),b.on("renderer:chapterUnload",d),c()}),a&&a()},EPUBJS.Hooks.register("beforeChapterDisplay").transculsions=function(a,b){var c=b.contents.querySelectorAll("[transclusion]");Array.prototype.slice.call(c).forEach(function(a){function c(){j=g,k=h,j>chapter.colWidth&&(d=chapter.colWidth/j,j=chapter.colWidth,k*=d),f.width=j,f.height=k}var d,e=a.getAttribute("ref"),f=document.createElement("iframe"),g=a.getAttribute("width"),h=a.getAttribute("height"),i=a.parentNode,j=g,k=h;c(),b.listenUntil("renderer:resized","renderer:chapterUnloaded",c),f.src=e,i.replaceChild(f,a)}),a&&a()}; -------------------------------------------------------------------------------- /app/static/js/libs/screenfull.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * screenfull 3 | * v3.3.0 - 2017-07-06 4 | * (c) Sindre Sorhus; MIT License 5 | */ 6 | 7 | !function(){"use strict";var a="undefined"!=typeof window&&void 0!==window.document?window.document:{},b="undefined"!=typeof module&&module.exports,c="undefined"!=typeof Element&&"ALLOW_KEYBOARD_INPUT"in Element,d=function(){for(var b,c=[["requestFullscreen","exitFullscreen","fullscreenElement","fullscreenEnabled","fullscreenchange","fullscreenerror"],["webkitRequestFullscreen","webkitExitFullscreen","webkitFullscreenElement","webkitFullscreenEnabled","webkitfullscreenchange","webkitfullscreenerror"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitCurrentFullScreenElement","webkitCancelFullScreen","webkitfullscreenchange","webkitfullscreenerror"],["mozRequestFullScreen","mozCancelFullScreen","mozFullScreenElement","mozFullScreenEnabled","mozfullscreenchange","mozfullscreenerror"],["msRequestFullscreen","msExitFullscreen","msFullscreenElement","msFullscreenEnabled","MSFullscreenChange","MSFullscreenError"]],d=0,e=c.length,f={};d 0 && this.size > 0 && this.fileData && this.fileData.buffer) { 93 | this.isValid = true; 94 | } 95 | 96 | bstream.readBytes(this.size); 97 | 98 | // Round up to 512-byte blocks. 99 | var remaining = 512 - this.size % 512; 100 | if (remaining > 0 && remaining < 512) { 101 | bstream.readBytes(remaining); 102 | } 103 | } else if (this.typeflag == 5) { 104 | info(" This is a directory.") 105 | } 106 | }; 107 | 108 | // Takes an ArrayBuffer of a tar file in 109 | // returns null on error 110 | // returns an array of DecompressedFile objects on success 111 | var untar = function(arrayBuffer) { 112 | currentFilename = ""; 113 | currentFileNumber = 0; 114 | currentBytesUnarchivedInFile = 0; 115 | currentBytesUnarchived = 0; 116 | totalUncompressedBytesInArchive = 0; 117 | totalFilesInArchive = 0; 118 | 119 | postMessage(new bitjs.archive.UnarchiveStartEvent()); 120 | var bstream = new bitjs.io.ByteStream(arrayBuffer); 121 | var localFiles = []; 122 | 123 | // While we don't encounter an empty block, keep making TarLocalFiles. 124 | while (bstream.peekNumber(4) != 0) { 125 | var oneLocalFile = new TarLocalFile(bstream); 126 | if (oneLocalFile && oneLocalFile.isValid) { 127 | localFiles.push(oneLocalFile); 128 | totalUncompressedBytesInArchive += oneLocalFile.size; 129 | } 130 | } 131 | totalFilesInArchive = localFiles.length; 132 | 133 | // got all local files, now sort them 134 | localFiles.sort(function(a,b) { 135 | var aname = a.filename.toLowerCase(); 136 | var bname = b.filename.toLowerCase(); 137 | return aname > bname ? 1 : -1; 138 | }); 139 | 140 | // report # files and total length 141 | if (localFiles.length > 0) { 142 | postProgress(); 143 | } 144 | 145 | // now do the shipping of each file 146 | for (var i = 0; i < localFiles.length; ++i) { 147 | var localfile = localFiles[i]; 148 | info("Sending file '" + localfile.filename + "' up"); 149 | 150 | // update progress 151 | currentFilename = localfile.filename; 152 | currentFileNumber = i; 153 | currentBytesUnarchivedInFile = localfile.size; 154 | currentBytesUnarchived += localfile.size; 155 | postMessage(new bitjs.archive.UnarchiveExtractEvent(localfile)); 156 | postProgress(); 157 | } 158 | 159 | postProgress(); 160 | 161 | postMessage(new bitjs.archive.UnarchiveFinishEvent()); 162 | }; 163 | 164 | // event.data.file has the ArrayBuffer. 165 | onmessage = function(event) { 166 | var ab = event.data.file; 167 | untar(ab); 168 | }; 169 | -------------------------------------------------------------------------------- /app/static/locale/ak/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | previous.title=Krataafa baako a etwa mu 17 | previous_label=Ekyiri-baako 18 | next.title=Krataafa a edi so baako 19 | next_label=Dea-ɛ-di-so-baako 20 | 21 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 22 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 23 | # representing the total number of pages in the document. 24 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 25 | # will be replaced by a number representing the currently visible page, 26 | # respectively a number representing the total number of pages in the document. 27 | 28 | zoom_out.title=Zuum pue 29 | zoom_out_label=Zuum ba abɔnten 30 | zoom_in.title=Zuum kɔ mu 31 | zoom_in_label=Zuum kɔ mu 32 | zoom.title=Zuum 33 | presentation_mode.title=Sesa kɔ Yɛkyerɛ Tebea mu 34 | presentation_mode_label=Yɛkyerɛ Tebea 35 | open_file.title=Bue Fael 36 | open_file_label=Bue 37 | print.title=Prente 38 | print_label=Prente 39 | download.title=Twe 40 | download_label=Twe 41 | bookmark.title=Seisei nhwɛ (fa anaaso bue wɔ tokuro foforo mu) 42 | bookmark_label=Seisei nhwɛ 43 | 44 | # Secondary toolbar and context menu 45 | 46 | 47 | # Document properties dialog box 48 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 49 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 50 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 51 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 52 | document_properties_title=Ti asɛm: 53 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 54 | # will be replaced by the creation/modification date, and time, of the PDF file. 55 | 56 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 57 | # a numerical per cent value. 58 | 59 | # Tooltips and alt text for side panel toolbar buttons 60 | # (the _label strings are alt text for the buttons, the .title strings are 61 | # tooltips) 62 | toggle_sidebar.title=Sɔ anaaso dum saedbaa 63 | toggle_sidebar_label=Sɔ anaaso dum saedbaa 64 | document_outline_label=Dɔkomɛnt bɔbea 65 | thumbs.title=Kyerɛ mfoniwaa 66 | thumbs_label=Mfoniwaa 67 | findbar.title=Hu wɔ dɔkomɛnt no mu 68 | findbar_label=Hu 69 | 70 | # Thumbnails panel item (tooltip and alt text for images) 71 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 72 | # number. 73 | thumb_page_title=Krataafa {{page}} 74 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 75 | # number. 76 | thumb_page_canvas=Krataafa ne mfoniwaa {{page}} 77 | 78 | # Find panel button title and messages 79 | find_label=Hunu: 80 | find_previous.title=San hu fres wɔ ekyiri baako 81 | find_previous_label=Ekyiri baako 82 | find_next.title=San hu fres no wɔ enim baako 83 | find_next_label=Ndiso 84 | find_highlight=Hyɛ bibiara nso 85 | find_match_case_label=Fa susu kaase 86 | find_reached_top=Edu krataafa ne soro, atoa so efiri ase 87 | find_reached_bottom=Edu krataafa n'ewiei, atoa so efiri soro 88 | find_not_found=Ennhu fres 89 | 90 | # Error panel labels 91 | error_more_info=Infɔmehyɛn bio a wɔka ho 92 | error_less_info=Te infɔmehyɛn bio a wɔka ho so 93 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 94 | # replaced by the PDF.JS version and build ID. 95 | error_version_info=PDF.js v{{vɛɛhyen}} (nsi: {{si}}) 96 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 97 | # english string describing the error. 98 | error_message=Nkrato: {{message}} 99 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 100 | # trace. 101 | error_stack=Staake: {{stack}} 102 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 103 | error_file=Fael: {{file}} 104 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 105 | error_line=Laen: {{line}} 106 | rendering_error=Mfomso bae wɔ bere a wɔ rekyerɛ krataafa no. 107 | 108 | # Predefined zoom values 109 | page_scale_width=Krataafa tɛtrɛtɛ 110 | page_scale_fit=Krataafa ehimtwa 111 | page_scale_auto=Zuum otomatik 112 | page_scale_actual=Kɛseyɛ ankasa 113 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 114 | # numerical scale value. 115 | 116 | # Loading indicator messages 117 | loading_error_indicator=Mfomso 118 | loading_error=Mfomso bae wɔ bere a wɔreloode PDF no. 119 | invalid_file_error=PDF fael no nndi mu anaaso ho atɔ kyima. 120 | missing_file_error=PDF fael no ayera. 121 | 122 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 123 | # "{{type}}" will be replaced with an annotation type from a list defined in 124 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 125 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 126 | text_annotation_type.alt=[{{type}} Tɛkst-nyiano] 127 | password_ok=OK 128 | 129 | printing_not_supported=Kɔkɔbɔ: Brawsa yi nnhyɛ daa mma prent ho kwan. 130 | printing_not_ready=Kɔkɔbɔ: Wɔnntwee PDF fael no nyinara mmbaee ama wo ɛ tumi aprente. 131 | web_fonts_disabled=Ɔedum wɛb-mfɔnt: nntumi mmfa PDF mfɔnt a wɔhyɛ mu nndi dwuma. 132 | document_colors_not_allowed=Wɔmma ho kwan sɛ PDF adɔkomɛnt de wɔn ara wɔn ahosu bɛdi dwuma: wɔ adum 'Ma ho kwan ma nkrataafa mpaw wɔn ara wɔn ahosu' wɔ brawsa yi mu. 133 | -------------------------------------------------------------------------------- /app/static/locale/csb/viewer.properties: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | # Main toolbar buttons (tooltips and alt text for images) 6 | previous.title=Pòprzédnô strona 7 | previous_label=Pòprzédnô 8 | next.title=Nôslédnô strona 9 | next_label=Nôslédnô 10 | 11 | # LOCALIZATION NOTE (page_label, page_of): 12 | # These strings are concatenated to form the "Page: X of Y" string. 13 | # Do not translate "{{pageCount}}", it will be substituted with a number 14 | # representing the total number of pages. 15 | page_label=Strona: 16 | page_of=z {{pageCount}} 17 | 18 | zoom_out.title=Zmniészë 19 | zoom_out_label=Zmniészë 20 | zoom_in.title=Zwikszë 21 | zoom_in_label=Wiôlgòsc 22 | zoom.title=Wiôlgòsc 23 | print.title=Drëkùjë 24 | print_label=Drëkùjë 25 | presentation_mode.title=Przéńdzë w trib prezentacje 26 | presentation_mode_label=Trib prezentacje 27 | open_file.title=Òtemkni lopk 28 | open_file_label=Òtemkni 29 | download.title=Zladënk 30 | download_label=Zladënk 31 | bookmark.title=Spamiãtôj wëzdrzatk (kòpérëje, abò òtemkni w nowim òknnie) 32 | bookmark_label=Aktualny wëzdrzatk 33 | 34 | find_label=Szëkôj: 35 | find_previous.title=Biéj do pòprzédnégò wënikù szëkbë 36 | find_previous_label=Pòprzédny 37 | find_next.title=Biéj do nôslédnégò wënikù szëkbë 38 | find_next_label=Nôslédny 39 | find_highlight=Pòdszkrzëni wszëtczé 40 | find_match_case_label=Rozeznôwôj miarã lëterów 41 | find_not_found=Nie nalôzł tekstu 42 | find_reached_bottom=Doszedł do kùńca dokùmentu, zaczinającë òd górë 43 | find_reached_top=Doszedł do pòczątkù dokùmentu, zaczinającë òd dołù 44 | 45 | toggle_sidebar.title=Pòsuwk wëbiérkù 46 | toggle_sidebar_label=Pòsuwk wëbiérkù 47 | 48 | outline.title=Wëskrzëni òbcéch dokùmentu 49 | outline_label=Òbcéch dokùmentu 50 | thumbs.title=Wëskrzëni miniaturë 51 | thumbs_label=Miniaturë 52 | findbar.title=Przeszëkôj dokùment 53 | findbar_label=Nalezë 54 | tools_label=Nôrzãdła 55 | first_page.title=Biéj do pierszi stronë 56 | first_page.label=Biéj do pierszi stronë 57 | last_page.label=Biéj do òstatny stronë 58 | invalid_file_error=Lëchi ôrt, abò pòpsëti lopk PDF. 59 | 60 | 61 | 62 | # Thumbnails panel item (tooltip and alt text for images) 63 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 64 | # number. 65 | thumb_page_title=Strona {{page}} 66 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 67 | # number. 68 | thumb_page_canvas=Miniatura stronë {{page}} 69 | 70 | # Error panel labels 71 | error_more_info=Wicy infòrmacje 72 | error_less_info=Mni infòrmacje 73 | error_close=Close 74 | error_version_info=PDF.js v{{version}} (build: {{build}}) 75 | 76 | 77 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 78 | # english string describing the error. 79 | error_message=Message: {{wiadło}} 80 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 81 | # trace. 82 | error_stack=Stack: {{stóg}} 83 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 84 | error_file=File: {{lopk}} 85 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 86 | error_line=Line: {{line}} 87 | rendering_error=Pòkôza sã fela przë renderowanim stronë. 88 | 89 | # Predefined zoom values 90 | page_scale_width=Szérzawa stronë 91 | page_scale_fit=Dopasëje stronã 92 | page_scale_auto=Aùtomatnô wiôlgòsc 93 | page_scale_actual=Naturalnô wiôlgòsc 94 | 95 | # Loading indicator messages 96 | # LOCALIZATION NOTE (error_line): "{{[percent}}" will be replaced with a percentage 97 | loading_error_indicator=Fela 98 | loading_error=Pòkôza sã fela przë wczëtiwanim PDFù. 99 | 100 | # LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip. 101 | # "{{[type}}" will be replaced with an annotation type from a list defined in 102 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 103 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 104 | 105 | request_password=PDF je zabezpieczony parolą: 106 | printing_not_supported = Òstrzéga: przezérnik nie je do kùńca wspieróny przez drëkôrze 107 | 108 | # Context menu 109 | page_rotate_cw.label=Òbkrãcë w prawò 110 | page_rotate_ccw.label=Òbkrãcë w lewò 111 | 112 | 113 | last_page.title=Biéj do pòprzédny stronë 114 | last_page_label=Biéj do pòprzédny stronë 115 | page_rotate_cw.title=Òbkrãcë w prawò 116 | page_rotate_cw_label=Òbkrãcë w prawò 117 | page_rotate_ccw.title=Òbkrãcë w lewò 118 | page_rotate_ccw_label=Òbkrãcë w lewò 119 | 120 | 121 | web_fonts_disabled=Sécowé czconczi są wëłączoné: włączë je, bë móc ùżiwac òsadzonëch czconków w lopkach PDF. 122 | 123 | 124 | missing_file_error=Felëje lopka PDF. 125 | printing_not_ready = Òstrzéga: lopk mùszi sã do kùńca wczëtac zanim gò mòże drëkòwac 126 | 127 | document_colors_disabled=Dokùmentë PDF nie mògą ù swòjich farwów: \'Pòzwòlë stronóm wëbierac swòje farwë\' je wëłączoné w przezérnikù. 128 | invalid_password=Lëchô parola. 129 | text_annotation_type.alt=[Adnotacjô {{type}}] 130 | 131 | tools.title=Tools 132 | first_page_label=Go to First Page 133 | 134 | 135 | -------------------------------------------------------------------------------- /app/static/locale/es-ES/viewer.properties: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | previous.title = Página anterior 6 | previous_label = Anterior 7 | next.title = Página siguiente 8 | next_label = Siguiente 9 | page.title = Página 10 | of_pages = de {{pagesCount}} 11 | page_of_pages = ({{pageNumber}} de {{pagesCount}}) 12 | zoom_out.title = Reducir 13 | zoom_out_label = Reducir 14 | zoom_in.title = Aumentar 15 | zoom_in_label = Aumentar 16 | zoom.title = Tamaño 17 | presentation_mode.title = Cambiar al modo presentación 18 | presentation_mode_label = Modo presentación 19 | open_file.title = Abrir archivo 20 | open_file_label = Abrir 21 | print.title = Imprimir 22 | print_label = Imprimir 23 | download.title = Descargar 24 | download_label = Descargar 25 | bookmark.title = Vista actual (copiar o abrir en una nueva ventana) 26 | bookmark_label = Vista actual 27 | tools.title = Herramientas 28 | tools_label = Herramientas 29 | first_page.title = Ir a la primera página 30 | first_page.label = Ir a la primera página 31 | first_page_label = Ir a la primera página 32 | last_page.title = Ir a la última página 33 | last_page.label = Ir a la última página 34 | last_page_label = Ir a la última página 35 | page_rotate_cw.title = Rotar en sentido horario 36 | page_rotate_cw.label = Rotar en sentido horario 37 | page_rotate_cw_label = Rotar en sentido horario 38 | page_rotate_ccw.title = Rotar en sentido antihorario 39 | page_rotate_ccw.label = Rotar en sentido antihorario 40 | page_rotate_ccw_label = Rotar en sentido antihorario 41 | hand_tool_enable.title = Activar herramienta mano 42 | hand_tool_enable_label = Activar herramienta mano 43 | hand_tool_disable.title = Desactivar herramienta mano 44 | hand_tool_disable_label = Desactivar herramienta mano 45 | document_properties.title = Propiedades del documento… 46 | document_properties_label = Propiedades del documento… 47 | document_properties_file_name = Nombre de archivo: 48 | document_properties_file_size = Tamaño de archivo: 49 | document_properties_kb = {{size_kb}} KB ({{size_b}} bytes) 50 | document_properties_mb = {{size_mb}} MB ({{size_b}} bytes) 51 | document_properties_title = Título: 52 | document_properties_author = Autor: 53 | document_properties_subject = Asunto: 54 | document_properties_keywords = Palabras clave: 55 | document_properties_creation_date = Fecha de creación: 56 | document_properties_modification_date = Fecha de modificación: 57 | document_properties_date_string = {{date}}, {{time}} 58 | document_properties_creator = Creador: 59 | document_properties_producer = Productor PDF: 60 | document_properties_version = Versión PDF: 61 | document_properties_page_count = Número de páginas: 62 | document_properties_close = Cerrar 63 | print_progress_message = Preparando documento para impresión… 64 | print_progress_percent = {{progress}}% 65 | print_progress_close = Cancelar 66 | toggle_sidebar.title = Cambiar barra lateral 67 | toggle_sidebar_label = Cambiar barra lateral 68 | document_outline.title = Mostrar resumen del documento (doble clic para expandir/contraer todos los elementos) 69 | document_outline_label = Resumen de documento 70 | attachments.title = Mostrar adjuntos 71 | attachments_label = Adjuntos 72 | thumbs.title = Mostrar miniaturas 73 | thumbs_label = Miniaturas 74 | findbar.title = Buscar en el documento 75 | findbar_label = Buscar 76 | thumb_page_title = Página {{page}} 77 | thumb_page_canvas = Miniatura de la página {{page}} 78 | find_label = Buscar: 79 | find_previous.title = Encontrar la anterior aparición de la frase 80 | find_previous_label = Anterior 81 | find_next.title = Encontrar la siguiente aparición de esta frase 82 | find_next_label = Siguiente 83 | find_highlight = Resaltar todos 84 | find_match_case_label = Coincidencia de mayús./minús. 85 | find_reached_top = Se alcanzó el inicio del documento, se continúa desde el final 86 | find_reached_bottom = Se alcanzó el final del documento, se continúa desde el inicio 87 | find_not_found = Frase no encontrada 88 | error_more_info = Más información 89 | error_less_info = Menos información 90 | error_close = Cerrar 91 | error_version_info = PDF.js v{{version}} (build: {{build}}) 92 | error_message = Mensaje: {{message}} 93 | error_stack = Pila: {{stack}} 94 | error_file = Archivo: {{file}} 95 | error_line = Línea: {{line}} 96 | rendering_error = Ocurrió un error al renderizar la página. 97 | page_scale_width = Anchura de la página 98 | page_scale_fit = Ajuste de la página 99 | page_scale_auto = Tamaño automático 100 | page_scale_actual = Tamaño real 101 | page_scale_percent = {{scale}}% 102 | loading_error_indicator = Error 103 | loading_error = Ocurrió un error al cargar el PDF. 104 | invalid_file_error = Fichero PDF no válido o corrupto. 105 | missing_file_error = No hay fichero PDF. 106 | unexpected_response_error = Respuesta inesperada del servidor. 107 | text_annotation_type.alt = [Anotación {{type}}] 108 | password_label = Introduzca la contraseña para abrir este archivo PDF. 109 | password_invalid = Contraseña no válida. Vuelva a intentarlo. 110 | password_ok = Aceptar 111 | password_cancel = Cancelar 112 | printing_not_supported = Advertencia: Imprimir no está totalmente soportado por este navegador. 113 | printing_not_ready = Advertencia: Este PDF no se ha cargado completamente para poder imprimirse. 114 | web_fonts_disabled = Las tipografías web están desactivadas: es imposible usar las tipografías PDF embebidas. 115 | document_colors_not_allowed = Los documentos PDF no tienen permitido usar sus propios colores: 'Permitir a las páginas elegir sus propios colores' está desactivado en el navegador. 116 | -------------------------------------------------------------------------------- /app/static/locale/it/viewer.properties: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | previous.title = Pagina precedente 6 | previous_label = Precedente 7 | next.title = Pagina successiva 8 | next_label = Successiva 9 | page.title = Pagina 10 | of_pages = di {{pagesCount}} 11 | page_of_pages = ({{pageNumber}} di {{pagesCount}}) 12 | zoom_out.title = Riduci zoom 13 | zoom_out_label = Riduci zoom 14 | zoom_in.title = Aumenta zoom 15 | zoom_in_label = Aumenta zoom 16 | zoom.title = Zoom 17 | presentation_mode.title = Passa alla modalità presentazione 18 | presentation_mode_label = Modalità presentazione 19 | open_file.title = Apri file 20 | open_file_label = Apri 21 | print.title = Stampa 22 | print_label = Stampa 23 | download.title = Scarica questo documento 24 | download_label = Download 25 | bookmark.title = Visualizzazione corrente (copia o apri in una nuova finestra) 26 | bookmark_label = Visualizzazione corrente 27 | tools.title = Strumenti 28 | tools_label = Strumenti 29 | first_page.title = Vai alla prima pagina 30 | first_page.label = Vai alla prima pagina 31 | first_page_label = Vai alla prima pagina 32 | last_page.title = Vai all’ultima pagina 33 | last_page.label = Vai all’ultima pagina 34 | last_page_label = Vai all’ultima pagina 35 | page_rotate_cw.title = Ruota in senso orario 36 | page_rotate_cw.label = Ruota in senso orario 37 | page_rotate_cw_label = Ruota in senso orario 38 | page_rotate_ccw.title = Ruota in senso antiorario 39 | page_rotate_ccw.label = Ruota in senso antiorario 40 | page_rotate_ccw_label = Ruota in senso antiorario 41 | hand_tool_enable.title = Attiva strumento mano 42 | hand_tool_enable_label = Attiva strumento mano 43 | hand_tool_disable.title = Disattiva strumento mano 44 | hand_tool_disable_label = Disattiva strumento mano 45 | document_properties.title = Proprietà del documento… 46 | document_properties_label = Proprietà del documento… 47 | document_properties_file_name = Nome file: 48 | document_properties_file_size = Dimensione file: 49 | document_properties_kb = {{size_kb}} kB ({{size_b}} byte) 50 | document_properties_mb = {{size_mb}} MB ({{size_b}} byte) 51 | document_properties_title = Titolo: 52 | document_properties_author = Autore: 53 | document_properties_subject = Oggetto: 54 | document_properties_keywords = Parole chiave: 55 | document_properties_creation_date = Data creazione: 56 | document_properties_modification_date = Data modifica: 57 | document_properties_date_string = {{date}}, {{time}} 58 | document_properties_creator = Autore originale: 59 | document_properties_producer = Produttore PDF: 60 | document_properties_version = Versione PDF: 61 | document_properties_page_count = Conteggio pagine: 62 | document_properties_close = Chiudi 63 | print_progress_message = Preparazione documento per la stampa… 64 | print_progress_percent = {{progress}}% 65 | print_progress_close = Annulla 66 | toggle_sidebar.title = Attiva/disattiva barra laterale 67 | toggle_sidebar_label = Attiva/disattiva barra laterale 68 | document_outline.title = Visualizza la struttura del documento (doppio clic per visualizzare/nascondere tutti gli elementi) 69 | document_outline_label = Struttura documento 70 | attachments.title = Visualizza allegati 71 | attachments_label = Allegati 72 | thumbs.title = Mostra le miniature 73 | thumbs_label = Miniature 74 | findbar.title = Trova nel documento 75 | findbar_label = Trova 76 | thumb_page_title = Pagina {{page}} 77 | thumb_page_canvas = Miniatura della pagina {{page}} 78 | find_label = Trova: 79 | find_previous.title = Trova l’occorrenza precedente del testo da cercare 80 | find_previous_label = Precedente 81 | find_next.title = Trova l’occorrenza successiva del testo da cercare 82 | find_next_label = Successivo 83 | find_highlight = Evidenzia 84 | find_match_case_label = Maiuscole/minuscole 85 | find_reached_top = Raggiunto l’inizio della pagina, continua dalla fine 86 | find_reached_bottom = Raggiunta la fine della pagina, continua dall’inizio 87 | find_not_found = Testo non trovato 88 | error_more_info = Ulteriori informazioni 89 | error_less_info = Nascondi dettagli 90 | error_close = Chiudi 91 | error_version_info = PDF.js v{{version}} (build: {{build}}) 92 | error_message = Messaggio: {{message}} 93 | error_stack = Stack: {{stack}} 94 | error_file = File: {{file}} 95 | error_line = Riga: {{line}} 96 | rendering_error = Si è verificato un errore durante il rendering della pagina. 97 | page_scale_width = Larghezza pagina 98 | page_scale_fit = Adatta a una pagina 99 | page_scale_auto = Zoom automatico 100 | page_scale_actual = Dimensioni effettive 101 | page_scale_percent = {{scale}}% 102 | loading_error_indicator = Errore 103 | loading_error = Si è verificato un errore durante il caricamento del PDF. 104 | invalid_file_error = File PDF non valido o danneggiato. 105 | missing_file_error = File PDF non disponibile. 106 | unexpected_response_error = Risposta imprevista del server 107 | text_annotation_type.alt = [Annotazione: {{type}}] 108 | password_label = Inserire la password per aprire questo file PDF. 109 | password_invalid = Password non corretta. Riprovare. 110 | password_ok = OK 111 | password_cancel = Annulla 112 | printing_not_supported = Attenzione: la stampa non è completamente supportata da questo browser. 113 | printing_not_ready = Attenzione: il PDF non è ancora stato caricato completamente per la stampa. 114 | web_fonts_disabled = I web font risultano disattivati: impossibile utilizzare i caratteri inclusi nel PDF. 115 | document_colors_not_allowed = Non è possibile visualizzare i colori originali definiti nel file PDF: l’opzione del browser “Consenti alle pagine di scegliere i propri colori invece di quelli impostati” è disattivata. 116 | -------------------------------------------------------------------------------- /app/static/locale/lg/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | previous.title=Omuko Ogubadewo 17 | next.title=Omuko Oguddako 18 | 19 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 20 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 21 | # representing the total number of pages in the document. 22 | of_pages=ku {{pagesCount}} 23 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 24 | # will be replaced by a number representing the currently visible page, 25 | # respectively a number representing the total number of pages in the document. 26 | 27 | zoom_out.title=Zimbulukusa 28 | zoom_out_label=Zimbulukusa 29 | zoom_in.title=Funza Munda 30 | zoom_in_label=Funza Munda 31 | zoom.title=Gezzamu 32 | open_file.title=Bikula Fayiro 33 | open_file_label=Ggulawo 34 | print.title=Fulumya 35 | print_label=Fulumya 36 | download.title=Tikula 37 | download_label=Tikula 38 | bookmark.title=Endabika eriwo (koppa oba gulawo mu diriisa epya) 39 | bookmark_label=Endabika Eriwo 40 | 41 | # Secondary toolbar and context menu 42 | 43 | 44 | # Document properties dialog box 45 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 46 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 47 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 48 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 49 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 50 | # will be replaced by the creation/modification date, and time, of the PDF file. 51 | 52 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 53 | # a numerical per cent value. 54 | 55 | # Tooltips and alt text for side panel toolbar buttons 56 | # (the _label strings are alt text for the buttons, the .title strings are 57 | # tooltips) 58 | document_outline_label=Ensalo ze Ekiwandiko 59 | thumbs.title=Laga Ekifanyi Mubufunze 60 | thumbs_label=Ekifanyi Mubufunze 61 | findbar_label=Zuula 62 | 63 | # Thumbnails panel item (tooltip and alt text for images) 64 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 65 | # number. 66 | thumb_page_title=Omuko {{page}} 67 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 68 | # number. 69 | thumb_page_canvas=Ekifananyi kyo Omuko Mubufunze {{page}} 70 | 71 | # Find panel button title and messages 72 | find_previous.title=Zuula awayise mukweddamu mumiteddera 73 | find_next.title=Zuula ekidako mukweddamu mumiteddera 74 | find_highlight=Londa byonna 75 | find_not_found=Emiteddera tezuuliddwa 76 | 77 | # Error panel labels 78 | error_more_info=Ebisingawo 79 | error_less_info=Mubumpimpi 80 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 81 | # replaced by the PDF.JS version and build ID. 82 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 83 | # english string describing the error. 84 | error_message=Obubaaka: {{message}} 85 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 86 | # trace. 87 | error_stack=Ebipangiddwa: {{stack}} 88 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 89 | error_file=Fayiro {{file}} 90 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 91 | error_line=Layini: {{line}} 92 | rendering_error=Wabadewo ensobi muku tekawo omuko. 93 | 94 | # Predefined zoom values 95 | page_scale_width=Obugazi bwo Omuko 96 | page_scale_fit=Okutuka kwo Omuko 97 | page_scale_auto=Okwefunza no Kwegeza 98 | page_scale_actual=Obunene Obutufu 99 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 100 | # numerical scale value. 101 | 102 | # Loading indicator messages 103 | loading_error_indicator=Ensobi 104 | loading_error=Wabadewo ensobi mukutika PDF. 105 | 106 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 107 | # "{{type}}" will be replaced with an annotation type from a list defined in 108 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 109 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 110 | text_annotation_type.alt=[{{type}} Enyonyola] 111 | password_ok=OK 112 | 113 | printing_not_supported=Okulaabula: Okulumya empapula tekuwagirwa enonyeso enno. 114 | -------------------------------------------------------------------------------- /app/static/locale/locale.properties: -------------------------------------------------------------------------------- 1 | [ach] 2 | @import url(ach/viewer.properties) 3 | 4 | [af] 5 | @import url(af/viewer.properties) 6 | 7 | [ak] 8 | @import url(ak/viewer.properties) 9 | 10 | [an] 11 | @import url(an/viewer.properties) 12 | 13 | [ar] 14 | @import url(ar/viewer.properties) 15 | 16 | [as] 17 | @import url(as/viewer.properties) 18 | 19 | [ast] 20 | @import url(ast/viewer.properties) 21 | 22 | [az] 23 | @import url(az/viewer.properties) 24 | 25 | [be] 26 | @import url(be/viewer.properties) 27 | 28 | [bg] 29 | @import url(bg/viewer.properties) 30 | 31 | [bn-BD] 32 | @import url(bn-BD/viewer.properties) 33 | 34 | [bn-IN] 35 | @import url(bn-IN/viewer.properties) 36 | 37 | [br] 38 | @import url(br/viewer.properties) 39 | 40 | [bs] 41 | @import url(bs/viewer.properties) 42 | 43 | [ca] 44 | @import url(ca/viewer.properties) 45 | 46 | [cs] 47 | @import url(cs/viewer.properties) 48 | 49 | [csb] 50 | @import url(csb/viewer.properties) 51 | 52 | [cy] 53 | @import url(cy/viewer.properties) 54 | 55 | [da] 56 | @import url(da/viewer.properties) 57 | 58 | [de] 59 | @import url(de/viewer.properties) 60 | 61 | [el] 62 | @import url(el/viewer.properties) 63 | 64 | [en-GB] 65 | @import url(en-GB/viewer.properties) 66 | 67 | [en-US] 68 | @import url(en-US/viewer.properties) 69 | 70 | [en-ZA] 71 | @import url(en-ZA/viewer.properties) 72 | 73 | [eo] 74 | @import url(eo/viewer.properties) 75 | 76 | [es-AR] 77 | @import url(es-AR/viewer.properties) 78 | 79 | [es-CL] 80 | @import url(es-CL/viewer.properties) 81 | 82 | [es-ES] 83 | @import url(es-ES/viewer.properties) 84 | 85 | [es-MX] 86 | @import url(es-MX/viewer.properties) 87 | 88 | [et] 89 | @import url(et/viewer.properties) 90 | 91 | [eu] 92 | @import url(eu/viewer.properties) 93 | 94 | [fa] 95 | @import url(fa/viewer.properties) 96 | 97 | [ff] 98 | @import url(ff/viewer.properties) 99 | 100 | [fi] 101 | @import url(fi/viewer.properties) 102 | 103 | [fr] 104 | @import url(fr/viewer.properties) 105 | 106 | [fy-NL] 107 | @import url(fy-NL/viewer.properties) 108 | 109 | [ga-IE] 110 | @import url(ga-IE/viewer.properties) 111 | 112 | [gd] 113 | @import url(gd/viewer.properties) 114 | 115 | [gl] 116 | @import url(gl/viewer.properties) 117 | 118 | [gu-IN] 119 | @import url(gu-IN/viewer.properties) 120 | 121 | [he] 122 | @import url(he/viewer.properties) 123 | 124 | [hi-IN] 125 | @import url(hi-IN/viewer.properties) 126 | 127 | [hr] 128 | @import url(hr/viewer.properties) 129 | 130 | [hu] 131 | @import url(hu/viewer.properties) 132 | 133 | [hy-AM] 134 | @import url(hy-AM/viewer.properties) 135 | 136 | [id] 137 | @import url(id/viewer.properties) 138 | 139 | [is] 140 | @import url(is/viewer.properties) 141 | 142 | [it] 143 | @import url(it/viewer.properties) 144 | 145 | [ja] 146 | @import url(ja/viewer.properties) 147 | 148 | [ka] 149 | @import url(ka/viewer.properties) 150 | 151 | [kk] 152 | @import url(kk/viewer.properties) 153 | 154 | [km] 155 | @import url(km/viewer.properties) 156 | 157 | [kn] 158 | @import url(kn/viewer.properties) 159 | 160 | [ko] 161 | @import url(ko/viewer.properties) 162 | 163 | [ku] 164 | @import url(ku/viewer.properties) 165 | 166 | [lg] 167 | @import url(lg/viewer.properties) 168 | 169 | [lij] 170 | @import url(lij/viewer.properties) 171 | 172 | [lt] 173 | @import url(lt/viewer.properties) 174 | 175 | [lv] 176 | @import url(lv/viewer.properties) 177 | 178 | [mai] 179 | @import url(mai/viewer.properties) 180 | 181 | [mk] 182 | @import url(mk/viewer.properties) 183 | 184 | [ml] 185 | @import url(ml/viewer.properties) 186 | 187 | [mn] 188 | @import url(mn/viewer.properties) 189 | 190 | [mr] 191 | @import url(mr/viewer.properties) 192 | 193 | [ms] 194 | @import url(ms/viewer.properties) 195 | 196 | [my] 197 | @import url(my/viewer.properties) 198 | 199 | [nb-NO] 200 | @import url(nb-NO/viewer.properties) 201 | 202 | [nl] 203 | @import url(nl/viewer.properties) 204 | 205 | [nn-NO] 206 | @import url(nn-NO/viewer.properties) 207 | 208 | [nso] 209 | @import url(nso/viewer.properties) 210 | 211 | [oc] 212 | @import url(oc/viewer.properties) 213 | 214 | [or] 215 | @import url(or/viewer.properties) 216 | 217 | [pa-IN] 218 | @import url(pa-IN/viewer.properties) 219 | 220 | [pl] 221 | @import url(pl/viewer.properties) 222 | 223 | [pt-BR] 224 | @import url(pt-BR/viewer.properties) 225 | 226 | [pt-PT] 227 | @import url(pt-PT/viewer.properties) 228 | 229 | [rm] 230 | @import url(rm/viewer.properties) 231 | 232 | [ro] 233 | @import url(ro/viewer.properties) 234 | 235 | [ru] 236 | @import url(ru/viewer.properties) 237 | 238 | [rw] 239 | @import url(rw/viewer.properties) 240 | 241 | [sah] 242 | @import url(sah/viewer.properties) 243 | 244 | [si] 245 | @import url(si/viewer.properties) 246 | 247 | [sk] 248 | @import url(sk/viewer.properties) 249 | 250 | [sl] 251 | @import url(sl/viewer.properties) 252 | 253 | [son] 254 | @import url(son/viewer.properties) 255 | 256 | [sq] 257 | @import url(sq/viewer.properties) 258 | 259 | [sr] 260 | @import url(sr/viewer.properties) 261 | 262 | [sv-SE] 263 | @import url(sv-SE/viewer.properties) 264 | 265 | [sw] 266 | @import url(sw/viewer.properties) 267 | 268 | [ta] 269 | @import url(ta/viewer.properties) 270 | 271 | [ta-LK] 272 | @import url(ta-LK/viewer.properties) 273 | 274 | [te] 275 | @import url(te/viewer.properties) 276 | 277 | [th] 278 | @import url(th/viewer.properties) 279 | 280 | [tl] 281 | @import url(tl/viewer.properties) 282 | 283 | [tn] 284 | @import url(tn/viewer.properties) 285 | 286 | [tr] 287 | @import url(tr/viewer.properties) 288 | 289 | [uk] 290 | @import url(uk/viewer.properties) 291 | 292 | [ur] 293 | @import url(ur/viewer.properties) 294 | 295 | [vi] 296 | @import url(vi/viewer.properties) 297 | 298 | [wo] 299 | @import url(wo/viewer.properties) 300 | 301 | [xh] 302 | @import url(xh/viewer.properties) 303 | 304 | [zh-CN] 305 | @import url(zh-CN/viewer.properties) 306 | 307 | [zh-TW] 308 | @import url(zh-TW/viewer.properties) 309 | 310 | [zu] 311 | @import url(zu/viewer.properties) 312 | 313 | -------------------------------------------------------------------------------- /app/static/locale/mn/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | 17 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 18 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 19 | # representing the total number of pages in the document. 20 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 21 | # will be replaced by a number representing the currently visible page, 22 | # respectively a number representing the total number of pages in the document. 23 | 24 | zoom.title=Тэлэлт 25 | open_file.title=Файл нээ 26 | open_file_label=Нээ 27 | 28 | # Secondary toolbar and context menu 29 | 30 | 31 | # Document properties dialog box 32 | document_properties_file_name=Файлын нэр: 33 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 34 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 35 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 36 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 37 | document_properties_title=Гарчиг: 38 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 39 | # will be replaced by the creation/modification date, and time, of the PDF file. 40 | 41 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 42 | # a numerical per cent value. 43 | 44 | # Tooltips and alt text for side panel toolbar buttons 45 | # (the _label strings are alt text for the buttons, the .title strings are 46 | # tooltips) 47 | findbar_label=Ол 48 | 49 | # Thumbnails panel item (tooltip and alt text for images) 50 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 51 | # number. 52 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 53 | # number. 54 | 55 | # Find panel button title and messages 56 | find_previous.title=Хайлтын өмнөх олдцыг харуулна 57 | find_next.title=Хайлтын дараагийн олдцыг харуулна 58 | find_not_found=Олдсонгүй 59 | 60 | # Error panel labels 61 | error_more_info=Нэмэлт мэдээлэл 62 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 63 | # replaced by the PDF.JS version and build ID. 64 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 65 | # english string describing the error. 66 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 67 | # trace. 68 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 69 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 70 | 71 | # Predefined zoom values 72 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 73 | # numerical scale value. 74 | 75 | # Loading indicator messages 76 | loading_error_indicator=Алдаа 77 | 78 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 79 | # "{{type}}" will be replaced with an annotation type from a list defined in 80 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 81 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 82 | password_ok=OK 83 | 84 | -------------------------------------------------------------------------------- /app/static/locale/nso/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | previous.title=Letlakala le fetilego 17 | previous_label=Fetilego 18 | next.title=Letlakala le latelago 19 | next_label=Latelago 20 | 21 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 22 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 23 | # representing the total number of pages in the document. 24 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 25 | # will be replaced by a number representing the currently visible page, 26 | # respectively a number representing the total number of pages in the document. 27 | 28 | zoom_out.title=Bušetša ka gare 29 | zoom_out_label=Bušetša ka gare 30 | zoom_in.title=Godišetša ka ntle 31 | zoom_in_label=Godišetša ka ntle 32 | zoom.title=Godiša 33 | presentation_mode.title=Fetogela go mokgwa wa tlhagišo 34 | presentation_mode_label=Mokgwa wa tlhagišo 35 | open_file.title=Bula faele 36 | open_file_label=Bula 37 | print.title=Gatiša 38 | print_label=Gatiša 39 | download.title=Laolla 40 | download_label=Laolla 41 | bookmark.title=Pono ya bjale (kopiša le go bula lefasetereng le leswa) 42 | bookmark_label=Tebelelo ya gona bjale 43 | 44 | # Secondary toolbar and context menu 45 | 46 | 47 | # Document properties dialog box 48 | document_properties_file_name=Leina la faele: 49 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 50 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 51 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 52 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 53 | document_properties_title=Thaetlele: 54 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 55 | # will be replaced by the creation/modification date, and time, of the PDF file. 56 | 57 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 58 | # a numerical per cent value. 59 | 60 | # Tooltips and alt text for side panel toolbar buttons 61 | # (the _label strings are alt text for the buttons, the .title strings are 62 | # tooltips) 63 | toggle_sidebar.title=Šielanya para ya ka thoko 64 | toggle_sidebar_label=Šielanya para ya ka thoko 65 | document_outline_label=Kakaretšo ya tokumente 66 | thumbs.title=Laetša dikhutšofatšo 67 | thumbs_label=Dikhutšofatšo 68 | findbar.title=Hwetša go tokumente 69 | findbar_label=Hwetša 70 | 71 | # Thumbnails panel item (tooltip and alt text for images) 72 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 73 | # number. 74 | thumb_page_title=Letlakala {{page}} 75 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 76 | # number. 77 | thumb_page_canvas=Khutšofatšo ya letlakala {{page}} 78 | 79 | # Find panel button title and messages 80 | find_label=Hwetša: 81 | find_previous.title=Hwetša tiragalo e fetilego ya sekafoko 82 | find_previous_label=Fetilego 83 | find_next.title=Hwetša tiragalo e latelago ya sekafoko 84 | find_next_label=Latelago 85 | find_highlight=Bonagatša tšohle 86 | find_match_case_label=Swantšha kheisi 87 | find_reached_top=Fihlile godimo ga tokumente, go tšwetšwe pele go tloga tlase 88 | find_reached_bottom=Fihlile mafelelong a tokumente, go tšwetšwe pele go tloga godimo 89 | find_not_found=Sekafoko ga sa hwetšwa 90 | 91 | # Error panel labels 92 | error_more_info=Tshedimošo e oketšegilego 93 | error_less_info=Tshedimošo ya tlasana 94 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 95 | # replaced by the PDF.JS version and build ID. 96 | error_version_info=PDF.js v{{version}} (build: {{build}}) 97 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 98 | # english string describing the error. 99 | error_message=Molaetša: {{message}} 100 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 101 | # trace. 102 | error_stack=Mokgobo: {{stack}} 103 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 104 | error_file=Faele: {{file}} 105 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 106 | error_line=Mothaladi: {{line}} 107 | rendering_error=Go diregile phošo ge go be go gafelwa letlakala. 108 | 109 | # Predefined zoom values 110 | page_scale_width=Bophara bja letlakala 111 | page_scale_fit=Go lekana ga letlakala 112 | page_scale_auto=Kgodišo ya maitirišo 113 | page_scale_actual=Bogolo bja kgonthe 114 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 115 | # numerical scale value. 116 | 117 | # Loading indicator messages 118 | loading_error_indicator=Phošo 119 | loading_error=Go diregile phošo ge go hlahlelwa PDF. 120 | invalid_file_error=Faele ye e sa šomego goba e senyegilego ya PDF. 121 | missing_file_error=Faele yeo e sego gona ya PDF. 122 | 123 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 124 | # "{{type}}" will be replaced with an annotation type from a list defined in 125 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 126 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 127 | text_annotation_type.alt=[{{type}} Tlhaloso] 128 | password_ok=LOKILE 129 | 130 | printing_not_supported=Temošo: Go gatiša ga go thekgwe ke praosara ye ka botlalo. 131 | printing_not_ready=Temošo: PDF ga ya hlahlelwa ka botlalo bakeng sa go gatišwa. 132 | web_fonts_disabled=Difonte tša wepe di šitišitšwe: ga e kgone go diriša difonte tša PDF tše khutišitšwego. 133 | -------------------------------------------------------------------------------- /app/static/locale/pl/viewer.properties: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | previous.title=Poprzednia strona 6 | previous_label=Poprzednia 7 | next.title=Następna strona 8 | next_label=Następna 9 | 10 | page.title==Strona: 11 | of_pages=z {{pagesCount}} 12 | page_of_pages=({{pageNumber}} z {{pagesCount}}) 13 | 14 | zoom_out.title=Pomniejszenie 15 | zoom_out_label=Pomniejsz 16 | zoom_in.title=Powiększenie 17 | zoom_in_label=Powiększ 18 | zoom.title=Skala 19 | presentation_mode.title=Przełącz na tryb prezentacji 20 | presentation_mode_label=Tryb prezentacji 21 | open_file.title=Otwieranie pliku 22 | open_file_label=Otwórz 23 | print.title=Drukowanie 24 | print_label=Drukuj 25 | download.title=Pobieranie 26 | download_label=Pobierz 27 | bookmark.title=Bieżąca pozycja (skopiuj lub otwórz jako odnośnik w nowym oknie) 28 | bookmark_label=Bieżąca pozycja 29 | 30 | tools.title=Narzędzia 31 | tools_label=Narzędzia 32 | first_page.title=Przechodzenie do pierwszej strony 33 | first_page.label=Przejdź do pierwszej strony 34 | first_page_label=Przejdź do pierwszej strony 35 | last_page.title=Przechodzenie do ostatniej strony 36 | last_page.label=Przejdź do ostatniej strony 37 | last_page_label=Przejdź do ostatniej strony 38 | page_rotate_cw.title=Obracanie zgodnie z ruchem wskazówek zegara 39 | page_rotate_cw.label=Obróć zgodnie z ruchem wskazówek zegara 40 | page_rotate_cw_label=Obróć zgodnie z ruchem wskazówek zegara 41 | page_rotate_ccw.title=Obracanie przeciwnie do ruchu wskazówek zegara 42 | page_rotate_ccw.label=Obróć przeciwnie do ruchu wskazówek zegara 43 | page_rotate_ccw_label=Obróć przeciwnie do ruchu wskazówek zegara 44 | 45 | hand_tool_enable.title=Włączanie narzędzia rączka 46 | hand_tool_enable_label=Włącz narzędzie rączka 47 | hand_tool_disable.title=Wyłączanie narzędzia rączka 48 | hand_tool_disable_label=Wyłącz narzędzie rączka 49 | 50 | document_properties.title=Właściwości dokumentu… 51 | document_properties_label=Właściwości dokumentu… 52 | document_properties_file_name=Nazwa pliku: 53 | document_properties_file_size=Rozmiar pliku: 54 | document_properties_kb={{size_kb}} KB ({{size_b}} b) 55 | document_properties_mb={{size_mb}} MB ({{size_b}} b) 56 | document_properties_title=Tytuł: 57 | document_properties_author=Autor: 58 | document_properties_subject=Temat: 59 | document_properties_keywords=Słowa kluczowe: 60 | document_properties_creation_date=Data utworzenia: 61 | document_properties_modification_date=Data modyfikacji: 62 | document_properties_date_string={{date}}, {{time}} 63 | document_properties_creator=Utworzony przez: 64 | document_properties_producer=PDF wyprodukowany przez: 65 | document_properties_version=Wersja PDF: 66 | document_properties_page_count=Liczba stron: 67 | document_properties_close=Zamknij 68 | 69 | print_progress_message=Przygotowywanie dokumentu do druku… 70 | print_progress_percent={{progress}}% 71 | print_progress_close=Anuluj 72 | 73 | toggle_sidebar.title=Przełączanie panelu bocznego 74 | toggle_sidebar_label=Przełącz panel boczny 75 | document_outline.title=Wyświetlanie zarysu dokumentu (podwójne kliknięcie rozwija lub zwija wszystkie pozycje) 76 | document_outline_label=Zarys dokumentu 77 | attachments.title=Wyświetlanie załączników 78 | attachments_label=Załączniki 79 | thumbs.title=Wyświetlanie miniaturek 80 | thumbs_label=Miniaturki 81 | findbar.title=Znajdź w dokumencie 82 | findbar_label=Znajdź 83 | 84 | thumb_page_title=Strona {{page}} 85 | thumb_page_canvas=Miniaturka strony {{page}} 86 | 87 | find_label=Znajdź: 88 | find_previous.title=Znajdź poprzednie wystąpienie tekstu 89 | find_previous_label=Poprzednie 90 | find_next.title=Znajdź następne wystąpienie tekstu 91 | find_next_label=Następne 92 | find_highlight=Podświetl wszystkie 93 | find_match_case_label=Rozróżniaj wielkość znaków 94 | find_reached_top=Osiągnięto początek dokumentu, kontynuacja od końca 95 | find_reached_bottom=Osiągnięto koniec dokumentu, kontynuacja od początku 96 | find_not_found=Tekst nieznaleziony 97 | 98 | error_more_info=Więcej informacji 99 | error_less_info=Mniej informacji 100 | error_close=Zamknij 101 | error_version_info=PDF.js v{{version}} (kompilacja: {{build}}) 102 | error_message=Wiadomość: {{message}} 103 | error_stack=Stos: {{stack}} 104 | error_file=Plik: {{file}} 105 | error_line=Wiersz: {{line}} 106 | rendering_error=Podczas renderowania strony wystąpił błąd. 107 | 108 | page_scale_width=Szerokość strony 109 | page_scale_fit=Dopasowanie strony 110 | page_scale_auto=Skala automatyczna 111 | page_scale_actual=Rozmiar rzeczywisty 112 | page_scale_percent={{scale}}% 113 | 114 | loading_error_indicator=Błąd 115 | loading_error=Podczas wczytywania dokumentu PDF wystąpił błąd. 116 | invalid_file_error=Nieprawidłowy lub uszkodzony plik PDF. 117 | missing_file_error=Brak pliku PDF. 118 | unexpected_response_error=Nieoczekiwana odpowiedź serwera. 119 | 120 | text_annotation_type.alt=[Adnotacja: {{type}}] 121 | password_label=Wprowadź hasło, aby otworzyć ten dokument PDF. 122 | password_invalid=Nieprawidłowe hasło. Proszę spróbować ponownie. 123 | password_ok=OK 124 | password_cancel=Anuluj 125 | 126 | printing_not_supported=Ostrzeżenie: Drukowanie nie jest w pełni obsługiwane przez przeglądarkę. 127 | printing_not_ready=Ostrzeżenie: Dokument PDF nie jest całkowicie wczytany, więc nie można go wydrukować. 128 | web_fonts_disabled=Czcionki sieciowe są wyłączone: nie można użyć osadzonych czcionek PDF. 129 | document_colors_not_allowed=Dokumenty PDF nie mogą używać własnych kolorów: Opcja „Pozwalaj stronom stosować inne kolory” w przeglądarce jest nieaktywna. 130 | -------------------------------------------------------------------------------- /app/static/locale/ru/viewer.properties: -------------------------------------------------------------------------------- 1 | # This Source Code Form is subject to the terms of the Mozilla Public 2 | # License, v. 2.0. If a copy of the MPL was not distributed with this 3 | # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 | 5 | previous.title = Предыдущая страница 6 | previous_label = Предыдущая 7 | next.title = Следующая страница 8 | next_label = Следующая 9 | page.title = Страница 10 | of_pages = из {{pagesCount}} 11 | page_of_pages = ({{pageNumber}} из {{pagesCount}}) 12 | zoom_out.title = Уменьшить 13 | zoom_out_label = Уменьшить 14 | zoom_in.title = Увеличить 15 | zoom_in_label = Увеличить 16 | zoom.title = Масштаб 17 | presentation_mode.title = Перейти в режим презентации 18 | presentation_mode_label = Режим презентации 19 | open_file.title = Открыть файл 20 | open_file_label = Открыть 21 | print.title = Печать 22 | print_label = Печать 23 | download.title = Загрузить 24 | download_label = Загрузить 25 | bookmark.title = Ссылка на текущий вид (скопировать или открыть в новом окне) 26 | bookmark_label = Текущий вид 27 | tools.title = Инструменты 28 | tools_label = Инструменты 29 | first_page.title = Перейти на первую страницу 30 | first_page.label = Перейти на первую страницу 31 | first_page_label = Перейти на первую страницу 32 | last_page.title = Перейти на последнюю страницу 33 | last_page.label = Перейти на последнюю страницу 34 | last_page_label = Перейти на последнюю страницу 35 | page_rotate_cw.title = Повернуть по часовой стрелке 36 | page_rotate_cw.label = Повернуть по часовой стрелке 37 | page_rotate_cw_label = Повернуть по часовой стрелке 38 | page_rotate_ccw.title = Повернуть против часовой стрелки 39 | page_rotate_ccw.label = Повернуть против часовой стрелки 40 | page_rotate_ccw_label = Повернуть против часовой стрелки 41 | hand_tool_enable.title = Включить Инструмент «Рука» 42 | hand_tool_enable_label = Включить Инструмент «Рука» 43 | hand_tool_disable.title = Отключить Инструмент «Рука» 44 | hand_tool_disable_label = Отключить Инструмент «Рука» 45 | document_properties.title = Свойства документа… 46 | document_properties_label = Свойства документа… 47 | document_properties_file_name = Имя файла: 48 | document_properties_file_size = Размер файла: 49 | document_properties_kb = {{size_kb}} КБ ({{size_b}} байт) 50 | document_properties_mb = {{size_mb}} МБ ({{size_b}} байт) 51 | document_properties_title = Заголовок: 52 | document_properties_author = Автор: 53 | document_properties_subject = Тема: 54 | document_properties_keywords = Ключевые слова: 55 | document_properties_creation_date = Дата создания: 56 | document_properties_modification_date = Дата изменения: 57 | document_properties_date_string = {{date}}, {{time}} 58 | document_properties_creator = Приложение: 59 | document_properties_producer = Производитель PDF: 60 | document_properties_version = Версия PDF: 61 | document_properties_page_count = Число страниц: 62 | document_properties_close = Закрыть 63 | print_progress_message = Подготовка документа к печати… 64 | print_progress_percent = {{progress}}% 65 | print_progress_close = Отмена 66 | toggle_sidebar.title = Открыть/закрыть боковую панель 67 | toggle_sidebar_label = Открыть/закрыть боковую панель 68 | document_outline.title = Показать содержание документа (двойной щелчок, чтобы развернуть/свернуть все элементы) 69 | document_outline_label = Содержание документа 70 | attachments.title = Показать вложения 71 | attachments_label = Вложения 72 | thumbs.title = Показать миниатюры 73 | thumbs_label = Миниатюры 74 | findbar.title = Найти в документе 75 | findbar_label = Найти 76 | thumb_page_title = Страница {{page}} 77 | thumb_page_canvas = Миниатюра страницы {{page}} 78 | find_label = Найти: 79 | find_previous.title = Найти предыдущее вхождение фразы в текст 80 | find_previous_label = Назад 81 | find_next.title = Найти следующее вхождение фразы в текст 82 | find_next_label = Далее 83 | find_highlight = Подсветить все 84 | find_match_case_label = С учётом регистра 85 | find_reached_top = Достигнут верх документа, продолжено снизу 86 | find_reached_bottom = Достигнут конец документа, продолжено сверху 87 | find_not_found = Фраза не найдена 88 | error_more_info = Детали 89 | error_less_info = Скрыть детали 90 | error_close = Закрыть 91 | error_version_info = PDF.js v{{version}} (сборка: {{build}}) 92 | error_message = Сообщение: {{message}} 93 | error_stack = Стeк: {{stack}} 94 | error_file = Файл: {{file}} 95 | error_line = Строка: {{line}} 96 | rendering_error = При создании страницы произошла ошибка. 97 | page_scale_width = По ширине страницы 98 | page_scale_fit = По размеру страницы 99 | page_scale_auto = Автоматически 100 | page_scale_actual = Реальный размер 101 | page_scale_percent = {{scale}}% 102 | loading_error_indicator = Ошибка 103 | loading_error = При загрузке PDF произошла ошибка. 104 | invalid_file_error = Некорректный или повреждённый PDF-файл. 105 | missing_file_error = PDF-файл отсутствует. 106 | unexpected_response_error = Неожиданный ответ сервера. 107 | text_annotation_type.alt = [Аннотация {{type}}] 108 | password_label = Введите пароль, чтобы открыть этот PDF-файл. 109 | password_invalid = Неверный пароль. Пожалуйста, попробуйте снова. 110 | password_ok = OK 111 | password_cancel = Отмена 112 | printing_not_supported = Предупреждение: В этом браузере не полностью поддерживается печать. 113 | printing_not_ready = Предупреждение: PDF не полностью загружен для печати. 114 | web_fonts_disabled = Веб-шрифты отключены: невозможно использовать встроенные PDF-шрифты. 115 | document_colors_not_allowed = PDF-документам не разрешено использовать свои цвета: в браузере отключён параметр «Разрешить веб-сайтам использовать свои цвета». 116 | -------------------------------------------------------------------------------- /app/static/locale/rw/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | 17 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 18 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 19 | # representing the total number of pages in the document. 20 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 21 | # will be replaced by a number representing the currently visible page, 22 | # respectively a number representing the total number of pages in the document. 23 | 24 | zoom.title=Ihindurangano 25 | open_file.title=Gufungura Dosiye 26 | open_file_label=Gufungura 27 | 28 | # Secondary toolbar and context menu 29 | 30 | 31 | # Document properties dialog box 32 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 33 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 34 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 35 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 36 | document_properties_title=Umutwe: 37 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 38 | # will be replaced by the creation/modification date, and time, of the PDF file. 39 | 40 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 41 | # a numerical per cent value. 42 | 43 | # Tooltips and alt text for side panel toolbar buttons 44 | # (the _label strings are alt text for the buttons, the .title strings are 45 | # tooltips) 46 | findbar_label=Gushakisha 47 | 48 | # Thumbnails panel item (tooltip and alt text for images) 49 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 50 | # number. 51 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 52 | # number. 53 | 54 | # Find panel button title and messages 55 | find_label="Gushaka:" 56 | find_previous.title=Gushaka aho uyu murongo ugaruka mbere y'aha 57 | find_next.title=Gushaka aho uyu murongo wongera kugaruka 58 | find_not_found=Umurongo ntubonetse 59 | 60 | # Error panel labels 61 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 62 | # replaced by the PDF.JS version and build ID. 63 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 64 | # english string describing the error. 65 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 66 | # trace. 67 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 68 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 69 | 70 | # Predefined zoom values 71 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 72 | # numerical scale value. 73 | 74 | # Loading indicator messages 75 | loading_error_indicator=Ikosa 76 | 77 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 78 | # "{{type}}" will be replaced with an annotation type from a list defined in 79 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 80 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 81 | password_invalid=Ijambo ry'ibanga ridahari. Wakongera ukagerageza 82 | password_ok=YEGO 83 | 84 | -------------------------------------------------------------------------------- /app/static/locale/sw/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | previous.title=Ukurasa Uliotangulia 17 | previous_label=Iliyotangulia 18 | next.title=Ukurasa Ufuatao 19 | next_label=Ifuatayo 20 | 21 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 22 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 23 | # representing the total number of pages in the document. 24 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 25 | # will be replaced by a number representing the currently visible page, 26 | # respectively a number representing the total number of pages in the document. 27 | 28 | zoom_out.title=Kuza Nje 29 | zoom_out_label=Kuza Nje 30 | zoom_in.title=Kuza Ndani 31 | zoom_in_label=Kuza Ndani 32 | zoom.title=Kuza 33 | presentation_mode.title=Badili kwa Hali ya Uwasilishaji 34 | presentation_mode_label=Hali ya Uwasilishaji 35 | open_file.title=Fungua Faili 36 | open_file_label=Fungua 37 | print.title=Chapisha 38 | print_label=Chapisha 39 | download.title=Pakua 40 | download_label=Pakua 41 | bookmark.title=Mwonekano wa sasa (nakili au ufungue katika dirisha mpya) 42 | bookmark_label=Mwonekano wa Sasa 43 | 44 | # Secondary toolbar and context menu 45 | 46 | 47 | # Document properties dialog box 48 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 49 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 50 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 51 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 52 | document_properties_title=Kichwa: 53 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 54 | # will be replaced by the creation/modification date, and time, of the PDF file. 55 | 56 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 57 | # a numerical per cent value. 58 | 59 | # Tooltips and alt text for side panel toolbar buttons 60 | # (the _label strings are alt text for the buttons, the .title strings are 61 | # tooltips) 62 | toggle_sidebar.title=Kibiano cha Upau wa Kando 63 | toggle_sidebar_label=Kibiano cha Upau wa Kando 64 | document_outline_label=Ufupisho wa Waraka 65 | thumbs.title=Onyesha Kijipicha 66 | thumbs_label=Vijipicha 67 | findbar.title=Pata katika Waraka 68 | findbar_label=Tafuta 69 | 70 | # Thumbnails panel item (tooltip and alt text for images) 71 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 72 | # number. 73 | thumb_page_title=Ukurasa {{ukurasa}} 74 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 75 | # number. 76 | thumb_page_canvas=Kijipicha cha ukurasa {{ukurasa}} 77 | 78 | # Find panel button title and messages 79 | find_label=Tafuta: 80 | find_previous.title=Tafuta tukio kabla ya msemo huu 81 | find_previous_label=Iliyotangulia 82 | find_next.title=Tafuta tukio linalofuata la msemo 83 | find_next_label=Ifuatayo 84 | find_highlight=Angazia yote 85 | find_match_case_label=Linganisha herufi 86 | find_reached_top=Imefika juu ya waraka, imeendelea kutoka chini 87 | find_reached_bottom=Imefika mwisho wa waraka, imeendelea kutoka juu 88 | find_not_found=Msemo hukupatikana 89 | 90 | # Error panel labels 91 | error_more_info=Maelezo Zaidi 92 | error_less_info=Maelezo Kidogo 93 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 94 | # replaced by the PDF.JS version and build ID. 95 | error_version_info=PDF.js v{{version}} (jenga: {{build}}) 96 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 97 | # english string describing the error. 98 | error_message=Ujumbe: {{message}} 99 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 100 | # trace. 101 | error_stack=Panganya: {{stack}} 102 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 103 | error_file=Faili: {{faili}} 104 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 105 | error_line=Laini: {{laini}} 106 | rendering_error=Hitilafu lilitokea wajati wa kutoa ukurasa 107 | 108 | # Predefined zoom values 109 | page_scale_width=Upana wa Ukurasa 110 | page_scale_fit=Usawa wa Ukurasa 111 | page_scale_auto=Ukuzaji wa Kiotomatiki 112 | page_scale_actual=Ukubwa Halisi 113 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 114 | # numerical scale value. 115 | 116 | # Loading indicator messages 117 | loading_error_indicator=Hitilafu 118 | loading_error=Hitilafu lilitokea wakati wa kupakia PDF. 119 | invalid_file_error=Faili ya PDF isiyohalali au potofu. 120 | missing_file_error=Faili ya PDF isiyopo. 121 | 122 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 123 | # "{{type}}" will be replaced with an annotation type from a list defined in 124 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 125 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 126 | text_annotation_type.alt=[{{type}} Ufafanuzi] 127 | password_ok=SAWA 128 | 129 | printing_not_supported=Onyo: Uchapishaji hauauniwi kabisa kwa kivinjari hiki. 130 | web_fonts_disabled=Fonti za tovuti zimelemazwa: haziwezi kutumia fonti za PDF zilizopachikwa. 131 | -------------------------------------------------------------------------------- /app/static/locale/ta-LK/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | 17 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 18 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 19 | # representing the total number of pages in the document. 20 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 21 | # will be replaced by a number representing the currently visible page, 22 | # respectively a number representing the total number of pages in the document. 23 | 24 | zoom.title=அளவு 25 | open_file.title=கோப்பினைத் திறக்க 26 | open_file_label=திறக்க 27 | 28 | # Secondary toolbar and context menu 29 | 30 | 31 | # Document properties dialog box 32 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 33 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 34 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 35 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 36 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 37 | # will be replaced by the creation/modification date, and time, of the PDF file. 38 | 39 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 40 | # a numerical per cent value. 41 | 42 | # Tooltips and alt text for side panel toolbar buttons 43 | # (the _label strings are alt text for the buttons, the .title strings are 44 | # tooltips) 45 | 46 | # Thumbnails panel item (tooltip and alt text for images) 47 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 48 | # number. 49 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 50 | # number. 51 | 52 | # Find panel button title and messages 53 | find_previous.title=இந்த சொற்றொடரின் முன்னைய நிகழ்வை தேடு 54 | find_next.title=இந்த சொற்றொடரின் அடுத்த நிகழ்வைத் தேடு 55 | 56 | # Error panel labels 57 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 58 | # replaced by the PDF.JS version and build ID. 59 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 60 | # english string describing the error. 61 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 62 | # trace. 63 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 64 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 65 | 66 | # Predefined zoom values 67 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 68 | # numerical scale value. 69 | 70 | # Loading indicator messages 71 | 72 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 73 | # "{{type}}" will be replaced with an annotation type from a list defined in 74 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 75 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 76 | password_ok=ஆம் 77 | 78 | -------------------------------------------------------------------------------- /app/static/locale/tl/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | previous.title=Naunang Pahina 17 | next.title=Sunod na Pahina 18 | 19 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 20 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 21 | # representing the total number of pages in the document. 22 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 23 | # will be replaced by a number representing the currently visible page, 24 | # respectively a number representing the total number of pages in the document. 25 | 26 | open_file.title=Magbukas ng file 27 | open_file_label=Buksan 28 | bookmark.title=Kasalukuyang tingin (kopyahin o buksan sa bagong window) 29 | bookmark_label=Kasalukuyang tingin 30 | 31 | # Secondary toolbar and context menu 32 | tools.title=Mga Tool 33 | tools_label=Mga Tool 34 | 35 | 36 | # Document properties dialog box 37 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 38 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 39 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 40 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 41 | document_properties_title=Pamagat: 42 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 43 | # will be replaced by the creation/modification date, and time, of the PDF file. 44 | 45 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 46 | # a numerical per cent value. 47 | 48 | # Tooltips and alt text for side panel toolbar buttons 49 | # (the _label strings are alt text for the buttons, the .title strings are 50 | # tooltips) 51 | thumbs.title=Ipakita ang mga Thumbnails 52 | findbar_label=Hanapin 53 | 54 | # Thumbnails panel item (tooltip and alt text for images) 55 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 56 | # number. 57 | thumb_page_title=Pahina {{page}} 58 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 59 | # number. 60 | thumb_page_canvas=Thumbnail ng Pahina {{page}} 61 | 62 | # Find panel button title and messages 63 | find_highlight=I-highlight lahat 64 | 65 | # Error panel labels 66 | error_more_info=Maraming Inpormasyon 67 | error_less_info=Maikling Inpormasyon 68 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 69 | # replaced by the PDF.JS version and build ID. 70 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 71 | # english string describing the error. 72 | error_message=Mensahe: {{message}} 73 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 74 | # trace. 75 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 76 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 77 | error_line=Linya: {{line}} 78 | rendering_error=May naganap na pagkakamali habang pagsasalin sa pahina. 79 | 80 | # Predefined zoom values 81 | page_scale_width=Haba ng Pahina 82 | page_scale_fit=ang pahina ay angkop 83 | page_scale_auto=awtomatikong pag-imbulog 84 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 85 | # numerical scale value. 86 | 87 | # Loading indicator messages 88 | loading_error=May maling nangyari habang kinakarga ang PDF. 89 | 90 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 91 | # "{{type}}" will be replaced with an annotation type from a list defined in 92 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 93 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 94 | password_ok=OK 95 | 96 | -------------------------------------------------------------------------------- /app/static/locale/tn/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | 17 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 18 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 19 | # representing the total number of pages in the document. 20 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 21 | # will be replaced by a number representing the currently visible page, 22 | # respectively a number representing the total number of pages in the document. 23 | 24 | zoom.title=Zuma/gogela 25 | open_file.title=Bula Faele 26 | open_file_label=Bula 27 | 28 | # Secondary toolbar and context menu 29 | 30 | hand_tool_disable.title=Thibela go dira ga sediriswa sa seatla 31 | hand_tool_disable_label=Thibela go dira ga sediriswa sa seatla 32 | 33 | # Document properties dialog box 34 | document_properties_file_name=Leina la faele: 35 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 36 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 37 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 38 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 39 | document_properties_title=Leina: 40 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 41 | # will be replaced by the creation/modification date, and time, of the PDF file. 42 | 43 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 44 | # a numerical per cent value. 45 | 46 | # Tooltips and alt text for side panel toolbar buttons 47 | # (the _label strings are alt text for the buttons, the .title strings are 48 | # tooltips) 49 | findbar_label=Batla 50 | 51 | # Thumbnails panel item (tooltip and alt text for images) 52 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 53 | # number. 54 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 55 | # number. 56 | 57 | # Find panel button title and messages 58 | find_previous.title=Batla tiragalo e e fetileng ya setlhopha sa mafoko 59 | find_next.title=Batla tiragalo e e latelang ya setlhopha sa mafoko 60 | find_not_found=Setlhopha sa mafoko ga se a bonwa 61 | 62 | # Error panel labels 63 | error_more_info=Tshedimosetso e Nngwe 64 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 65 | # replaced by the PDF.JS version and build ID. 66 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 67 | # english string describing the error. 68 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 69 | # trace. 70 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 71 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 72 | 73 | # Predefined zoom values 74 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 75 | # numerical scale value. 76 | 77 | # Loading indicator messages 78 | loading_error_indicator=Phoso 79 | 80 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 81 | # "{{type}}" will be replaced with an annotation type from a list defined in 82 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 83 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 84 | password_ok=Siame 85 | 86 | web_fonts_disabled=Mefutatlhaka ya Webo ga e dire: ga e kgone go dirisa mofutatlhaka wa PDF o tsentsweng. 87 | -------------------------------------------------------------------------------- /app/static/locale/wo/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | previous.title=Xët wi jiitu 17 | previous_label=Bi jiitu 18 | next.title=Xët wi ci topp 19 | next_label=Bi ci topp 20 | 21 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 22 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 23 | # representing the total number of pages in the document. 24 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 25 | # will be replaced by a number representing the currently visible page, 26 | # respectively a number representing the total number of pages in the document. 27 | 28 | zoom_out.title=Wàññi 29 | zoom_out_label=Wàññi 30 | zoom_in.title=Yaatal 31 | zoom_in_label=Yaatal 32 | zoom.title=Yambalaŋ 33 | presentation_mode.title=Wañarñil ci anamu wone 34 | presentation_mode_label=Anamu Wone 35 | open_file.title=Ubbi benn dencukaay 36 | open_file_label=Ubbi 37 | print.title=Móol 38 | print_label=Móol 39 | download.title=Yeb yi 40 | download_label=Yeb yi 41 | bookmark.title=Wone bi taxaw (duppi walla ubbi palanteer bu bees) 42 | bookmark_label=Wone bi feeñ 43 | 44 | # Secondary toolbar and context menu 45 | 46 | 47 | # Document properties dialog box 48 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 49 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 50 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 51 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 52 | document_properties_title=Bopp: 53 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 54 | # will be replaced by the creation/modification date, and time, of the PDF file. 55 | 56 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 57 | # a numerical per cent value. 58 | 59 | # Tooltips and alt text for side panel toolbar buttons 60 | # (the _label strings are alt text for the buttons, the .title strings are 61 | # tooltips) 62 | thumbs.title=Wone nataal yu ndaw yi 63 | thumbs_label=Nataal yu ndaw yi 64 | findbar.title=Gis ci biir jukki bi 65 | findbar_label=Wut 66 | 67 | # Thumbnails panel item (tooltip and alt text for images) 68 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 69 | # number. 70 | thumb_page_title=Xët {{xët}} 71 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 72 | # number. 73 | thumb_page_canvas=Wiñet bu xët{{xët}} 74 | 75 | # Find panel button title and messages 76 | find_label=Wut: 77 | find_previous.title=Seet beneen kaddu bu ni mel te jiitu 78 | find_previous_label=Bi jiitu 79 | find_next.title=Seet beneen kaddu bu ni mel 80 | find_next_label=Bi ci topp 81 | find_highlight=Melaxal lépp 82 | find_match_case_label=Sàmm jëmmalin wi 83 | find_reached_top=Jot nañu ndorteel xët wi, kontine dale ko ci suuf 84 | find_reached_bottom=Jot nañu jeexitalu xët wi, kontine ci ndorte 85 | find_not_found=Gisiñu kaddu gi 86 | 87 | # Error panel labels 88 | error_more_info=Xibaar yu gën bari 89 | error_less_info=Xibaar yu gën bari 90 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 91 | # replaced by the PDF.JS version and build ID. 92 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 93 | # english string describing the error. 94 | error_message=Bataaxal: {{bataaxal}} 95 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 96 | # trace. 97 | error_stack=Juug: {{stack}} 98 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 99 | error_file=Dencukaay: {{file}} 100 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 101 | error_line=Rëdd : {{line}} 102 | rendering_error=Am njumte bu am bi xët bi di wonewu. 103 | 104 | # Predefined zoom values 105 | page_scale_width=Yaatuwaay bu mët 106 | page_scale_fit=Xët lëmm 107 | page_scale_auto=Yambalaŋ ci saa si 108 | page_scale_actual=Dayo bi am 109 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 110 | # numerical scale value. 111 | 112 | # Loading indicator messages 113 | loading_error_indicator=Njumte 114 | loading_error=Am na njumte ci yebum dencukaay PDF bi. 115 | invalid_file_error=Dencukaay PDF bi baaxul walla mu sankar. 116 | 117 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 118 | # "{{type}}" will be replaced with an annotation type from a list defined in 119 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 120 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 121 | text_annotation_type.alt=[Karmat {{type}}] 122 | password_ok=OK 123 | password_cancel=Neenal 124 | 125 | printing_not_supported=Artu: Joowkat bii nanguwul lool mool. 126 | -------------------------------------------------------------------------------- /app/templates/auth/change_kindle_mail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'bootstrap/wtf.html' as wtf %} 3 | 4 | {% block page_content %} 5 |

Change Kindle Email

6 |
7 |
8 | {{ wtf.quick_form(form, button_map={'submit': 'primary'}) }} 9 |
10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /app/templates/auth/change_password.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'bootstrap/wtf.html' as wtf %} 3 | 4 | {% block page_content %} 5 |

Change Your Password

6 |
7 |
8 | {{ wtf.quick_form(form, button_map={'submit': 'primary'}) }} 9 |
10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /app/templates/auth/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% import 'bootstrap/wtf.html' as wtf %} 3 | 4 | {% block page_content %} 5 |

Sign In

6 |
7 |
8 | {{ wtf.quick_form(form, button_map={'submit': 'primary'}) }} 9 |
10 |
11 |
12 |

New User? Click to Register!

13 |

14 | Forgot Your Password? 15 | Click to Reset It 16 |

17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /app/templates/auth/register.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'bootstrap/wtf.html' as wtf %} 3 | 4 | {% block page_content %} 5 |

Register

6 |
7 |
8 | {{ wtf.quick_form(form, button_map={'submit': 'primary'}) }} 9 |
10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /app/templates/auth/reset_password.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'bootstrap/wtf.html' as wtf %} 3 | 4 | {% block page_content %} 5 |

Reset Your Password

6 |
7 |
8 | {{ wtf.quick_form(form, button_map={'submit': 'primary'}) }} 9 |
10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /app/templates/auth/reset_password_request.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'bootstrap/wtf.html' as wtf %} 3 | 4 | {% block page_content %} 5 |

Reset Password

6 |
7 |
8 | {{ wtf.quick_form(form, button_map={'submit': 'primary'}) }} 9 |
10 |
11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /app/templates/auth/unconfirmed.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% import 'bootstrap/wtf.html' as wtf %} 3 | 4 | {% block page_content %} 5 |

Hello, {{ current_user.email }}!

6 |

You have not confirmed your account yet.

7 |

8 | Before you can access this site you need to confirm your account. 9 | Check your inbox, you should have received an email with a confirmation link. 10 |

11 |

12 | Need another confirmation email? 13 | Click here 14 |

15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /app/templates/base.html: -------------------------------------------------------------------------------- 1 | {% extends "bootstrap/base.html" %} 2 | {% import "bootstrap/fixes.html" as fixes %} 3 | {% import "bootstrap/utils.html" as utils %} 4 | {% from "bootstrap/pagination.html" import render_pagination %} 5 | 6 | {% block title %}51-read | {{ title }}{% endblock %} 7 | 8 | {% block head %} 9 | {{ super() }} 10 | {{fixes.ie8()}} 11 | 12 | 13 | {% endblock %} 14 | 15 | {% block navbar %} 16 | 76 | {% endblock %} 77 | 78 | {% block content %} 79 |
80 |
81 | {{ utils.flashed_messages(messages, dismissible=True) }} 82 |
83 | 84 | {% block page_content %}{% endblock %} 85 | 86 | {% if pagination %} 87 | {{ render_pagination(pagination) }} 88 | {% endif %} 89 |
90 | 91 | 104 | 105 | {% endblock %} 106 | 107 | {% block styles %} 108 | {{ super() }} 109 | 110 | {% endblock styles %} 111 | 112 | {% block scripts %} 113 | {{ super() }} 114 | 121 | {% endblock %} 122 | -------------------------------------------------------------------------------- /app/templates/email/confirm.html: -------------------------------------------------------------------------------- 1 |

Dear {{ user.email }},

2 |

Welcome to 51read!

3 |

4 | To confirm your account please 5 | 6 | click here 7 | . 8 |

9 |

Alternatively, you can paste the following link in your browser's address bar:

10 |

{{ url_for('auth.confirm', token=token, _external=True) }}

11 |

Sincerely,

12 |

The 51read Team

13 |

Note: replies to this email address are not monitored.

-------------------------------------------------------------------------------- /app/templates/email/confirm.txt: -------------------------------------------------------------------------------- 1 | Dear {{ user.email }}, 2 | 3 | Welcome to 51read! 4 | 5 | To confirm your account please click on the following link: 6 | 7 | {{ url_for('auth.confirm', token=token, _external=True) }} 8 | 9 | Sincerely, 10 | 11 | The 51read Team 12 | 13 | Note: replies to this email address are not monitored. -------------------------------------------------------------------------------- /app/templates/email/reset_password.html: -------------------------------------------------------------------------------- 1 |

Dear {{ user.email }},

2 |

3 | To reset your password 4 | 5 | click here 6 | . 7 |

8 |

Alternatively, you can paste the following link in your browser's address bar:

9 |

{{ url_for('auth.reset_password', token=token, _external=True) }}

10 |

If you have not requested a password reset simply ignore this message.

11 |

Sincerely,

12 |

The 51read Team

13 |

Note: replies to this email address are not monitored.

-------------------------------------------------------------------------------- /app/templates/email/reset_password.txt: -------------------------------------------------------------------------------- 1 | Dear {{ user.email }}, 2 | 3 | To reset your password click on the following link: 4 | 5 | {{ url_for('auth.reset_password', token=token, _external=True) }} 6 | 7 | If you have not requested a password reset simply ignore this message. 8 | 9 | Sincerely, 10 | 11 | The 51read Team 12 | 13 | Note: replies to this email address are not monitored. -------------------------------------------------------------------------------- /app/templates/errors/403.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block page_content %} 4 | 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /app/templates/errors/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block page_content %} 4 | 7 | {% endblock %} -------------------------------------------------------------------------------- /app/templates/errors/500.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block page_content %} 4 | 7 | {% endblock %} -------------------------------------------------------------------------------- /app/templates/main/convert_book.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% import 'bootstrap/wtf.html' as wtf %} 3 | 4 | {% block page_content %} 5 |

Convert Book

6 |
7 |
8 | 19 |
20 |

{{ book.title | truncate(15, True) }}

21 |

22 | {% for author in book.authors %} 23 | {{ author.name | replace('|',',') }} 24 | {% if not loop.last %} 25 | & 26 | {% endif %} 27 | {% endfor %} 28 |

29 | {% if book.ratings.__len__() > 0 %} 30 |
31 | {% for number in range((book.ratings[0].rating/2)|int(2)) %} 32 | 33 | {% if loop.last and loop.index < 5 %} 34 | {% for numer in range(5 - loop.index) %} 35 | 36 | {% endfor %} 37 | {% endif %} 38 | {% endfor %} 39 |
40 | {% endif %} 41 |
42 |
43 |
44 | {{ wtf.quick_form(form, button_map={'submit': 'primary'}) }} 45 |
46 |
47 | {% endblock %} 48 | -------------------------------------------------------------------------------- /app/templates/main/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block page_content %} 4 |
5 | {% if books %} 6 | {% for book in books %} 7 |
8 | 32 |
33 | {% for file in book.data %} 34 | {{ file.format.lower() }} 36 | {% endfor %} 37 |
38 | 39 |
40 |

{{ book.title | truncate(20, True) }}

41 |

42 | {% for author in book.authors %} 43 | {{ author.name | replace('|',',') }} 44 | {% if not loop.last %} 45 | & 46 | {% endif %} 47 | {% endfor %} 48 |

49 | {% if book.ratings.__len__() > 0 %} 50 |
51 | {% for number in range((book.ratings[0].rating/2)|int(2)) %} 52 | 53 | {% if loop.last and loop.index < 5 %} 54 | {% for numer in range(5 - loop.index) %} 55 | 56 | {% endfor %} 57 | {% endif %} 58 | {% endfor %} 59 |
60 | {% endif %} 61 |
62 |
63 | {% endfor %} 64 | {% else %} 65 |

No Results

66 | {% endif %} 67 |
68 | {% endblock %} 69 | 70 | 71 | -------------------------------------------------------------------------------- /app/templates/main/readepub.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 78 | 79 |
80 |
81 |
82 | Menu 83 |
84 |
85 | 86 |   –   87 | 88 |
89 |
90 | Bookmark 91 | Settings 92 | Fullscreen 93 | Exit 94 |
95 |
96 | 97 |
98 | 99 |
100 | 101 |
102 |
103 | 104 | 115 |
116 | 117 | 122 | 123 | -------------------------------------------------------------------------------- /app/templates/main/readtxt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ title }} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 110 | 111 | 112 |
113 | 114 |
115 | 116 | Exit 117 |
118 | 119 | 178 | 179 | -------------------------------------------------------------------------------- /app/utils/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/9/6 15:35 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com -------------------------------------------------------------------------------- /app/utils/book_format.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/9/8 12:44 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import logging 6 | import os 7 | 8 | from app import uploads 9 | from app.utils import pdf, epub, fb2 10 | from app.utils.book_meta import default_meta 11 | 12 | logger = logging.getLogger("book_format") 13 | 14 | 15 | def process(abs_file_path, file_path, file_name, file_extension): 16 | meta = None 17 | try: 18 | if "PDF" == file_extension.upper(): 19 | meta = pdf.get_pdf_meta(abs_file_path, file_path, file_name, file_extension.upper()) 20 | elif "EPUB" == file_extension.upper(): 21 | meta = epub.get_epub_meta(abs_file_path, file_path, file_name, file_extension.upper()) 22 | elif "FB2" == file_extension.upper(): 23 | meta = fb2.get_fb2_meta(abs_file_path, file_path, file_name, file_extension.upper()) 24 | except Exception as ex: 25 | logger.warning('cannot parse metadata, using default: %s', ex) 26 | 27 | if meta: 28 | return meta 29 | else: 30 | return default_meta(file_name, file_path, file_name, file_extension.upper(), 31 | os.path.getsize(uploads.path(abs_file_path))) 32 | -------------------------------------------------------------------------------- /app/utils/book_meta.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/9/8 14:19 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | from collections import namedtuple 6 | 7 | BookMeta = namedtuple('BookMeta', 8 | ['title', 'author', 'cover_path', 'description', 'tags', 9 | 'series', 'series_id', 'languages', 'file_path', 'file_name', 'file_extension', 'file_size']) 10 | 11 | 12 | def default_meta(title, file_path, file_name, file_extension, file_size): 13 | return BookMeta( 14 | title=title, 15 | author="Unknown", 16 | cover_path="", 17 | description="", 18 | tags="", 19 | series="", 20 | series_id="", 21 | languages="", 22 | file_path=file_path, 23 | file_name=file_name, 24 | file_extension=file_extension, 25 | file_size=file_size) 26 | -------------------------------------------------------------------------------- /app/utils/email.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/9/6 15:35 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import os 6 | from threading import Thread 7 | from flask import render_template, current_app, url_for 8 | from flask_mail import Message, Attachment 9 | from app import mail, uploads 10 | 11 | 12 | def send_async_email(app, msg): 13 | with app.app_context(): 14 | mail.send(msg) 15 | 16 | 17 | def send_email(subject, sender, recipients, text_body, html_body, 18 | attachments=None, sync=False): 19 | msg = Message(subject, sender=sender, recipients=recipients) 20 | msg.body = text_body 21 | msg.html = html_body 22 | if attachments: 23 | for attachment in attachments: 24 | msg.attach(**attachment) 25 | if sync: 26 | mail.send(msg) 27 | else: 28 | Thread(target=send_async_email, args=(current_app._get_current_object(), msg)).start() 29 | 30 | 31 | def send_confirmation_email(user): 32 | token = user.generate_confirmation_token() 33 | send_email(subject='[51read] Confirm Your Account', 34 | sender=current_app.config['ADMIN'], 35 | recipients=[user.email], 36 | text_body=render_template('email/confirm.txt', 37 | user=user, token=token), 38 | html_body=render_template('email/confirm.html', 39 | user=user, token=token)) 40 | 41 | 42 | def send_password_reset_email(user): 43 | token = user.generate_reset_password_token() 44 | send_email('[51read] Reset Your Password', 45 | sender=current_app.config['ADMIN'], 46 | recipients=[user.email], 47 | text_body=render_template('email/reset_password.txt', 48 | user=user, token=token), 49 | html_body=render_template('email/reset_password.html', 50 | user=user, token=token)) 51 | 52 | 53 | def send_book(user, book): 54 | """Send email with attachments""" 55 | kindle_formats = ['mobi', 'pdf', 'txt'] 56 | formats = {} 57 | for entry in book.data: 58 | if entry.format.lower() in kindle_formats: 59 | formats[entry.format.lower()] = entry.name + "." + entry.format.lower() 60 | 61 | filename = None 62 | if 'mobi' in formats: 63 | filename = formats['mobi'] 64 | elif 'pdf' in formats: 65 | filename = formats['pdf'] 66 | elif 'txt' in formats: 67 | filename = formats['txt'] 68 | 69 | if filename: 70 | with current_app.open_resource(os.path.join(current_app.config['UPLOAD_FOLDER'], book.path, filename)) as fp: 71 | attachment = dict(filename=filename, content_type='application/octet-stream', data=fp.read()) 72 | send_email('[51read] Send book %s' % book.title, 73 | sender=current_app.config['ADMIN'], 74 | recipients=[user.kindle_email], 75 | text_body="", 76 | html_body="", 77 | attachments=[attachment]) 78 | else: 79 | return "Could not find any allowed kindle formats suitable for sending by e-mail('mobi', 'pdf', 'txt')" 80 | 81 | -------------------------------------------------------------------------------- /app/utils/epub.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/9/8 12:44 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import os 6 | import zipfile 7 | 8 | import lxml.html 9 | from iso639 import languages as isoLanguages 10 | 11 | from app import uploads 12 | from app.utils.book_meta import BookMeta 13 | 14 | etree = lxml.html.etree 15 | 16 | 17 | def extract_cover(zip_file, zip_cover_path, file_path): 18 | if zip_cover_path: 19 | cf = zip_file.read(zip_cover_path) 20 | prefix = os.path.splitext(file_path)[0] 21 | cover_path = prefix + '.jpg' 22 | with open(uploads.path(cover_path), 'wb') as image: 23 | image.write(cf) 24 | return cover_path 25 | else: 26 | return '' 27 | 28 | 29 | def get_epub_meta(abs_file_path, file_path, file_name, file_extension): 30 | ns = { 31 | 'n': 'urn:oasis:names:tc:opendocument:xmlns:container', 32 | 'pkg': 'http://www.idpf.org/2007/opf', 33 | 'dc': 'http://purl.org/dc/elements/1.1/' 34 | } 35 | 36 | epubZip = zipfile.ZipFile(abs_file_path) 37 | txt = epubZip.read('META-INF/container.xml') 38 | tree = etree.fromstring(txt) 39 | cfname = tree.xpath('n:rootfiles/n:rootfile/@full-path', namespaces=ns)[0] 40 | cf = epubZip.read(cfname) 41 | tree = etree.fromstring(cf) 42 | 43 | cfpath = os.path.dirname(cfname) 44 | 45 | p = tree.xpath('/pkg:package/pkg:metadata', namespaces=ns)[0] 46 | 47 | epub_metadata = {} 48 | 49 | for s in ['title', 'description', 'creator', 'language', 'subject']: 50 | tmp = p.xpath('dc:%s/text()' % s, namespaces=ns) 51 | if len(tmp) > 0: 52 | epub_metadata[s] = p.xpath('dc:%s/text()' % s, namespaces=ns)[0] 53 | else: 54 | epub_metadata[s] = "Unknown" 55 | 56 | if epub_metadata['subject'] == "Unknown": 57 | epub_metadata['subject'] = '' 58 | 59 | if epub_metadata['description'] == "Unknown": 60 | description = tree.xpath("//*[local-name() = 'description']/text()") 61 | if len(description) > 0: 62 | epub_metadata['description'] = description 63 | else: 64 | epub_metadata['description'] = "" 65 | 66 | if epub_metadata['language'] == "Unknown": 67 | epub_metadata['language'] = "" 68 | else: 69 | lang = epub_metadata['language'].split('-', 1)[0].lower() 70 | if len(lang) == 2: 71 | epub_metadata['language'] = isoLanguages.get(part1=lang).name 72 | elif len(lang) == 3: 73 | epub_metadata['language'] = isoLanguages.get(part3=lang).name 74 | else: 75 | epub_metadata['language'] = "" 76 | 77 | series = tree.xpath("/pkg:package/pkg:metadata/pkg:meta[@name='calibre:series']/@content", namespaces=ns) 78 | if len(series) > 0: 79 | epub_metadata['series'] = series[0] 80 | else: 81 | epub_metadata['series'] = '' 82 | 83 | series_id = tree.xpath("/pkg:package/pkg:metadata/pkg:meta[@name='calibre:series_index']/@content", namespaces=ns) 84 | if len(series_id) > 0: 85 | epub_metadata['series_id'] = series_id[0] 86 | else: 87 | epub_metadata['series_id'] = '1' 88 | 89 | coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='cover-image']/@href", namespaces=ns) 90 | cover_path = '' 91 | if len(coversection) > 0: 92 | zip_cover_path = os.path.join(cfpath, coversection[0]).replace('\\', '/') 93 | cover_path = extract_cover(epubZip, zip_cover_path, abs_file_path) 94 | else: 95 | meta_cover = tree.xpath("/pkg:package/pkg:metadata/pkg:meta[@name='cover']/@content", namespaces=ns) 96 | if len(meta_cover) > 0: 97 | coversection = tree.xpath("/pkg:package/pkg:manifest/pkg:item[@id='" + meta_cover[0] + "']/@href", 98 | namespaces=ns) 99 | if len(coversection) > 0: 100 | filetype = coversection[0].rsplit('.', 1)[-1] 101 | if filetype == "xhtml" or filetype == "html": # if cover is (x)html format 102 | markup = epubZip.read(os.path.join(cfpath, coversection[0])) 103 | markupTree = etree.fromstring(markup) 104 | # no matter xhtml or html with no namespace 105 | imgsrc = markupTree.xpath("//*[local-name() = 'img']/@src") 106 | # imgsrc maybe startwith "../"" so fullpath join then relpath to cwd 107 | zip_cover_path = os.path.relpath( 108 | os.path.join(os.path.dirname(os.path.join(cfpath, coversection[0])), imgsrc[0])).replace('\\', 109 | '/') 110 | cover_path = extract_cover(epubZip, zip_cover_path, abs_file_path) 111 | else: 112 | zip_cover_path = os.path.join(cfpath, coversection[0]).replace('\\', '/') 113 | cover_path = extract_cover(epubZip, zip_cover_path, abs_file_path) 114 | 115 | if not epub_metadata['title']: 116 | title = file_name 117 | else: 118 | title = epub_metadata['title'] 119 | 120 | return BookMeta( 121 | title=title, 122 | author=epub_metadata['creator'], 123 | cover_path=cover_path, 124 | description=epub_metadata['description'], 125 | tags=epub_metadata['subject'], 126 | series=epub_metadata['series'], 127 | series_id=epub_metadata['series_id'], 128 | languages=epub_metadata['language'], 129 | file_path=file_path, 130 | file_name=file_name, 131 | file_extension=file_extension, 132 | file_size=os.path.getsize(abs_file_path)) 133 | -------------------------------------------------------------------------------- /app/utils/fb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/9/8 12:44 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import os 6 | from xml import etree 7 | 8 | from app import uploads 9 | from app.utils.book_meta import BookMeta 10 | 11 | 12 | def get_fb2_meta(abs_file_path, file_path, file_name, file_extension): 13 | ns = { 14 | 'fb': 'http://www.gribuser.ru/xml/fictionbook/2.0', 15 | 'l': 'http://www.w3.org/1999/xlink', 16 | } 17 | 18 | tree = etree.fromstring(open(abs_file_path).read()) 19 | 20 | def get_author(element): 21 | last_name = element.xpath('fb:last-name/text()', namespaces=ns) 22 | if len(last_name): 23 | last_name = last_name[0] 24 | else: 25 | last_name = '' 26 | middle_name = element.xpath('fb:middle-name/text()', namespaces=ns) 27 | if len(middle_name): 28 | middle_name = middle_name[0] 29 | else: 30 | middle_name = '' 31 | first_name = element.xpath('fb:first-name/text()', namespaces=ns) 32 | if len(first_name): 33 | first_name = first_name[0] 34 | else: 35 | first_name = '' 36 | return first_name + ' ' + middle_name + ' ' + last_name 37 | authors = tree.xpath('/fb:FictionBook/fb:description/fb:title-info/fb:author', namespaces=ns) 38 | author = str(", ".join(map(get_author, authors))) 39 | 40 | title = tree.xpath('/fb:FictionBook/fb:description/fb:title-info/fb:book-title/text()', namespaces=ns) 41 | if len(title): 42 | title = str(title[0]) 43 | else: 44 | title = file_name 45 | description = tree.xpath('/fb:FictionBook/fb:description/fb:publish-info/fb:book-name/text()', namespaces=ns) 46 | if len(description): 47 | description = str(description[0]) 48 | else: 49 | description = '' 50 | 51 | return BookMeta( 52 | title=title, 53 | author=author, 54 | cover_path="", 55 | description=description, 56 | tags="", 57 | series="", 58 | series_id="", 59 | languages="", 60 | file_path=file_path, 61 | file_name=file_name, 62 | file_extension=file_extension, 63 | file_size=os.path.getsize(abs_file_path)) 64 | -------------------------------------------------------------------------------- /app/utils/helper.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/9/9 20:49 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import os 6 | import re 7 | import subprocess 8 | import sys 9 | from shutil import rmtree 10 | 11 | from flask import current_app 12 | 13 | 14 | def get_sorted_author(value): 15 | try: 16 | regexes = ["^(JR|SR)\.?$", "^I{1,3}\.?$", "^IV\.?$"] 17 | combined = "(" + ")|(".join(regexes) + ")" 18 | value = value.split(" ") 19 | if re.match(combined, value[-1].upper()): 20 | value2 = value[-2] + ", " + " ".join(value[:-2]) + " " + value[-1] 21 | else: 22 | value2 = value[-1] + ", " + " ".join(value[:-1]) 23 | except Exception: 24 | value2 = value 25 | return value2 26 | 27 | 28 | def resolve_folder_conflict(base_path, folder): 29 | if os.path.exists(os.path.join(base_path, folder)): 30 | count = 0 31 | while True: 32 | count = count + 1 33 | new_folder = '%s(%d)' % (folder, count) 34 | if not os.path.exists(os.path.join(base_path, new_folder)): 35 | return new_folder 36 | else: 37 | return folder 38 | 39 | 40 | def delete_book(file_path): 41 | if os.path.exists(file_path): 42 | rmtree(file_path) 43 | 44 | 45 | def convert_book(convert_tool_path, old_file_path, new_file_path): 46 | try: 47 | if (os.name == 'posix') and (sys.version_info > (3, 0)): 48 | command = [convert_tool_path, old_file_path, new_file_path] 49 | p = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True) 50 | except OSError as e: 51 | return "ebook-converter failed" 52 | p.communicate() 53 | if (0 == p.returncode) and (os.path.isfile(new_file_path)): 54 | return None 55 | else: 56 | return "ebook-converter failed" 57 | -------------------------------------------------------------------------------- /app/utils/pdf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/9/8 14:48 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import os 6 | 7 | from PyPDF2 import PdfFileReader 8 | 9 | from app.utils.book_meta import BookMeta 10 | 11 | 12 | def get_pdf_meta(abs_file_path, file_path, file_name, file_extension): 13 | pdf = PdfFileReader(open(abs_file_path, 'rb')) 14 | doc_info = pdf.getDocumentInfo() 15 | 16 | if doc_info is not None: 17 | author = doc_info.author if doc_info.author else "Unknown" 18 | title = doc_info.title if doc_info.title else file_name 19 | subject = doc_info.subject 20 | else: 21 | author = "Unknown" 22 | title = file_name 23 | subject = "" 24 | 25 | return BookMeta( 26 | title=title, 27 | author=author, 28 | cover_path="", 29 | description=subject, 30 | tags="", 31 | series="", 32 | series_id="", 33 | languages="", 34 | file_path=file_path, 35 | file_name=file_name, 36 | file_extension=file_extension, 37 | file_size=os.path.getsize(abs_file_path)) 38 | 39 | -------------------------------------------------------------------------------- /app/utils/qiniuutils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/9/16 23:55 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import requests 6 | from flask import app 7 | from qiniu import Auth, put_file 8 | 9 | 10 | # Access Key 和 Secret Key 11 | access_key = app.config['QINIU_ACCESS_KEY'] 12 | secret_key = app.config['QINIU_SECRET_KEY'] 13 | 14 | # 构建鉴权对象 15 | q = Auth(access_key, secret_key) 16 | 17 | # 要上传的空间 18 | bucket_name = app.config['QINIU_BUCKET_NAME'] 19 | bucket_domain = app.config['QINIU_DOMAIN'] 20 | 21 | 22 | def qiniu_upload_file(source_file, save_file_name): 23 | token = q.upload_token(bucket_name, save_file_name) 24 | ret, info = put_file(token, save_file_name, source_file.stream) 25 | if info.status_code == 200: 26 | return bucket_domain + save_file_name 27 | else: 28 | return None 29 | 30 | 31 | def qiniu_download_file(file_name): 32 | base_url = 'http://%s/%s' % (bucket_domain, file_name) 33 | private_url = q.private_download_url(base_url) 34 | r = requests.get(private_url) 35 | if r.status_code == 200: 36 | return True 37 | else: 38 | return False 39 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/6/7 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import os 6 | 7 | from dotenv import load_dotenv 8 | 9 | basedir = os.path.abspath(os.path.dirname(__file__)) 10 | load_dotenv(os.path.join(basedir, '.env')) 11 | 12 | 13 | class Config: 14 | SECRET_KEY = os.environ.get('SECRET_KEY', 'you-will-never-guess') 15 | 16 | # recaptcha 17 | # RECAPTCHA_PUBLIC_KEY = '6LeYIbsSAAAAACRPIllxA7wvXjIE411PfdB2gt2J' 18 | # RECAPTCHA_PRIVATE_KEY = '6LeYIbsSAAAAAJezaIq3Ft_hSTo0YtyeFG-JgRtu' 19 | # RECAPTCHA_OPTIONS = dict(theme='custom') 20 | 21 | # SQLAlchemy config 22 | SQLALCHEMY_TRACK_MODIFICATIONS = False 23 | SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL', 24 | 'sqlite:///' + os.path.join(basedir, 'app.db')) 25 | BOOKS_PER_PAGE = 20 26 | 27 | # mail config 28 | MAIL_SERVER = os.environ.get('MAIL_SERVER') 29 | MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25) 30 | MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None 31 | MAIL_USE_SSL = os.environ.get('MAIL_USE_SSL') is not None 32 | MAIL_USERNAME = os.environ.get('MAIL_USERNAME') 33 | MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') 34 | 35 | # admin config 36 | ADMIN = os.environ.get('ADMIN') 37 | 38 | # file upload 39 | UPLOADS_DEFAULT_DEST = os.environ.get('UPLOAD_FOLDER', basedir) 40 | UPLOAD_FOLDER = os.path.join(basedir, 'uploads') 41 | 42 | # qiniu 43 | QINIU_ACCESS_KEY = os.environ.get('QINIU_ACCESS_KEY') 44 | QINIU_SECRET_KEY = os.environ.get('QINIU_SECRET_KEY') 45 | QINIU_BUCKET_NAME = os.environ.get('QINIU_BUCKET_NAME') 46 | QINIU_DOMAIN = os.environ.get('QINIU_DOMAIN') 47 | 48 | CONVERT_TOOL_PATH = os.environ.get('CONVERT_TOOL_PATH', None) 49 | 50 | # log to stdout 51 | LOG_TO_STDOUT = os.environ.get('LOG_TO_STDOUT') 52 | 53 | 54 | class TestingConfig(Config): 55 | TESTING = True 56 | 57 | # SQLAlchemy config 58 | SQLALCHEMY_DATABASE_URI = 'sqlite://' 59 | 60 | -------------------------------------------------------------------------------- /migrations/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /migrations/alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # template used to generate migration files 5 | # file_template = %%(rev)s_%%(slug)s 6 | 7 | # set to 'true' to run the environment during 8 | # the 'revision' command, regardless of autogenerate 9 | # revision_environment = false 10 | 11 | 12 | # Logging configuration 13 | [loggers] 14 | keys = root,sqlalchemy,alembic 15 | 16 | [handlers] 17 | keys = console 18 | 19 | [formatters] 20 | keys = generic 21 | 22 | [logger_root] 23 | level = WARN 24 | handlers = console 25 | qualname = 26 | 27 | [logger_sqlalchemy] 28 | level = WARN 29 | handlers = 30 | qualname = sqlalchemy.engine 31 | 32 | [logger_alembic] 33 | level = INFO 34 | handlers = 35 | qualname = alembic 36 | 37 | [handler_console] 38 | class = StreamHandler 39 | args = (sys.stderr,) 40 | level = NOTSET 41 | formatter = generic 42 | 43 | [formatter_generic] 44 | format = %(levelname)-5.5s [%(name)s] %(message)s 45 | datefmt = %H:%M:%S 46 | -------------------------------------------------------------------------------- /migrations/env.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | from alembic import context 3 | from sqlalchemy import engine_from_config, pool 4 | from logging.config import fileConfig 5 | import logging 6 | 7 | # this is the Alembic Config object, which provides 8 | # access to the values within the .ini file in use. 9 | config = context.config 10 | 11 | # Interpret the config file for Python logging. 12 | # This line sets up loggers basically. 13 | fileConfig(config.config_file_name) 14 | logger = logging.getLogger('alembic.env') 15 | 16 | # add your model's MetaData object here 17 | # for 'autogenerate' support 18 | # from myapp import mymodel 19 | # target_metadata = mymodel.Base.metadata 20 | from flask import current_app 21 | config.set_main_option('sqlalchemy.url', 22 | current_app.config.get('SQLALCHEMY_DATABASE_URI')) 23 | target_metadata = current_app.extensions['migrate'].db.metadata 24 | 25 | # other values from the config, defined by the needs of env.py, 26 | # can be acquired: 27 | # my_important_option = config.get_main_option("my_important_option") 28 | # ... etc. 29 | 30 | 31 | def run_migrations_offline(): 32 | """Run migrations in 'offline' mode. 33 | 34 | This configures the context with just a URL 35 | and not an Engine, though an Engine is acceptable 36 | here as well. By skipping the Engine creation 37 | we don't even need a DBAPI to be available. 38 | 39 | Calls to context.execute() here emit the given string to the 40 | script output. 41 | 42 | """ 43 | url = config.get_main_option("sqlalchemy.url") 44 | context.configure(url=url) 45 | 46 | with context.begin_transaction(): 47 | context.run_migrations() 48 | 49 | 50 | def run_migrations_online(): 51 | """Run migrations in 'online' mode. 52 | 53 | In this scenario we need to create an Engine 54 | and associate a connection with the context. 55 | 56 | """ 57 | 58 | # this callback is used to prevent an auto-migration from being generated 59 | # when there are no changes to the schema 60 | # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html 61 | def process_revision_directives(context, revision, directives): 62 | if getattr(config.cmd_opts, 'autogenerate', False): 63 | script = directives[0] 64 | if script.upgrade_ops.is_empty(): 65 | directives[:] = [] 66 | logger.info('No changes in schema detected.') 67 | 68 | engine = engine_from_config(config.get_section(config.config_ini_section), 69 | prefix='sqlalchemy.', 70 | poolclass=pool.NullPool) 71 | 72 | connection = engine.connect() 73 | context.configure(connection=connection, 74 | target_metadata=target_metadata, 75 | process_revision_directives=process_revision_directives, 76 | **current_app.extensions['migrate'].configure_args) 77 | 78 | try: 79 | with context.begin_transaction(): 80 | context.run_migrations() 81 | finally: 82 | connection.close() 83 | 84 | if context.is_offline_mode(): 85 | run_migrations_offline() 86 | else: 87 | run_migrations_online() 88 | -------------------------------------------------------------------------------- /migrations/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /migrations/versions/9324a63ac6e1_users_table.py: -------------------------------------------------------------------------------- 1 | """users table 2 | 3 | Revision ID: 9324a63ac6e1 4 | Revises: 5 | Create Date: 2018-09-08 22:30:28.225552 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '9324a63ac6e1' 14 | down_revision = None 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade(): 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | op.create_table('users', 22 | sa.Column('id', sa.Integer(), nullable=False), 23 | sa.Column('email', sa.String(length=120), nullable=True), 24 | sa.Column('password_hash', sa.String(length=128), nullable=True), 25 | sa.Column('member_since', sa.DateTime(), nullable=True), 26 | sa.Column('last_seen', sa.DateTime(), nullable=True), 27 | sa.Column('confirmed', sa.Boolean(), nullable=True), 28 | sa.PrimaryKeyConstraint('id') 29 | ) 30 | op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True) 31 | # ### end Alembic commands ### 32 | 33 | 34 | def downgrade(): 35 | # ### commands auto generated by Alembic - please adjust! ### 36 | op.drop_index(op.f('ix_users_email'), table_name='users') 37 | op.drop_table('users') 38 | # ### end Alembic commands ### 39 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.6.6 -------------------------------------------------------------------------------- /tests/test_basics.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/9/3 17:38 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import unittest 6 | from flask import current_app 7 | from app import create_app, db 8 | from config import TestingConfig 9 | 10 | 11 | class BasicsTestCase(unittest.TestCase): 12 | def setUp(self): 13 | self.app = create_app(TestingConfig) 14 | self.app_context = self.app.app_context() 15 | self.app_context.push() 16 | db.create_all() 17 | 18 | def tearDown(self): 19 | db.session.remove() 20 | db.drop_all() 21 | self.app_context.pop() 22 | 23 | def test_app_exists(self): 24 | self.assertFalse(current_app is None) 25 | 26 | def test_app_is_testing(self): 27 | self.assertTrue(current_app.config['TESTING']) 28 | -------------------------------------------------------------------------------- /tests/test_user_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2018/8/30 16:00 3 | # @Author : geekspeng 4 | # @Email : geekspeng@icloud.com 5 | import unittest 6 | from app import create_app, db 7 | from app.models.users import Users 8 | from config import TestingConfig 9 | 10 | 11 | class UserModelTestCase(unittest.TestCase): 12 | def setUp(self): 13 | self.app = create_app(TestingConfig) 14 | self.app_context = self.app.app_context() 15 | self.app_context.push() 16 | db.create_all() 17 | 18 | def tearDown(self): 19 | db.session.remove() 20 | db.drop_all() 21 | self.app_context.pop() 22 | 23 | def test_check_password(self): 24 | u = Users(email='your-email@example.com') 25 | u.set_password('cat') 26 | self.assertFalse(u.check_password('dog')) 27 | self.assertTrue(u.check_password('cat')) 28 | --------------------------------------------------------------------------------