├── .gitignore ├── ISSUE_TEMPLATE.md ├── LazyLibrarian.app └── Contents │ ├── Info.plist │ ├── MacOS │ └── applet │ ├── PkgInfo │ └── Resources │ ├── Scripts │ └── main.scpt │ ├── applet.icns │ ├── applet.rsrc │ └── description.rtfd │ └── TXT.rtf ├── LazyLibrarian.py ├── README.md ├── UNITTESTING.md ├── cherrypy ├── LICENSE.txt ├── __init__.py ├── _cpchecker.py ├── _cpcompat.py ├── _cpcompat_subprocess.py ├── _cpconfig.py ├── _cpdispatch.py ├── _cperror.py ├── _cplogging.py ├── _cpmodpy.py ├── _cpnative_server.py ├── _cpreqbody.py ├── _cprequest.py ├── _cpserver.py ├── _cpthreadinglocal.py ├── _cptools.py ├── _cptree.py ├── _cpwsgi.py ├── _cpwsgi_server.py ├── cherryd ├── favicon.ico ├── lazylibrarian.note ├── lib │ ├── __init__.py │ ├── auth.py │ ├── auth_basic.py │ ├── auth_digest.py │ ├── caching.py │ ├── covercp.py │ ├── cpstats.py │ ├── cptools.py │ ├── encoding.py │ ├── gctools.py │ ├── http.py │ ├── httpauth.py │ ├── httputil.py │ ├── jsontools.py │ ├── lockfile.py │ ├── locking.py │ ├── profiler.py │ ├── reprconf.py │ ├── sessions.py │ ├── static.py │ └── xmlrpcutil.py ├── process │ ├── __init__.py │ ├── plugins.py │ ├── servers.py │ ├── win32.py │ └── wspbus.py ├── scaffold │ ├── __init__.py │ ├── apache-fcgi.conf │ ├── example.conf │ ├── site.conf │ └── static │ │ └── made_with_cherrypy_small.png └── wsgiserver │ ├── __init__.py │ ├── ssl_builtin.py │ ├── ssl_pyopenssl.py │ ├── wsgiserver2.py │ └── wsgiserver3.py ├── data ├── README.md ├── css │ ├── bookstrap.css │ ├── bootstrap.min.css │ ├── data_table.css │ ├── datatables.min.css │ ├── fontawesome │ │ └── fontawesome-all.css │ ├── ipad_landscape.css │ ├── ipad_portrait.css │ ├── iphone4_portrait.css │ ├── mobile.css │ ├── style.css │ ├── summernote.css │ └── webfonts │ │ ├── fa-regular-400.eot │ │ ├── fa-regular-400.ttf │ │ ├── fa-regular-400.woff │ │ ├── fa-regular-400.woff2 │ │ ├── fa-solid-900.eot │ │ ├── fa-solid-900.ttf │ │ ├── fa-solid-900.woff │ │ └── fa-solid-900.woff2 ├── images │ ├── 0-stars.png │ ├── 1-stars.png │ ├── 2-stars.png │ ├── 3-stars.png │ ├── 4-stars.png │ ├── 5-stars.png │ ├── back_disabled.jpg │ ├── back_enabled.jpg │ ├── checkmark.png │ ├── favicon.ico │ ├── forward_disabled.jpg │ ├── forward_enabled.jpg │ ├── icon_search.png │ ├── lazylibrarian.png │ ├── ll.ico │ ├── ll.png │ ├── ll128.png │ ├── ll16.png │ ├── ll192.png │ ├── ll256.png │ ├── ll32.png │ ├── ll48.png │ ├── ll512.png │ ├── ll64.png │ ├── loader_black.gif │ ├── manifest.json │ ├── nav │ │ ├── auth.png │ │ ├── blank.png │ │ ├── book.png │ │ ├── config.png │ │ ├── hist.png │ │ ├── logs.png │ │ ├── mags.png │ │ ├── manage.png │ │ └── series.png │ ├── nocover.jpg │ ├── nocover.png │ ├── nophoto.png │ ├── nostar.png │ ├── restart.png │ ├── shutdown.png │ ├── sort_asc.png │ ├── sort_asc_disabled.png │ ├── sort_both.png │ ├── sort_desc.png │ ├── sort_desc_disabled.png │ ├── sprite.png │ ├── sprite1.png │ └── star.png ├── interfaces │ ├── bookstrap │ │ ├── audio.html │ │ ├── author.html │ │ ├── base.html │ │ ├── books.html │ │ ├── choosetype.html │ │ ├── config.html │ │ ├── coverwall.html │ │ ├── dbupdate.html │ │ ├── dlresult.html │ │ ├── editauthor.html │ │ ├── editbook.html │ │ ├── history.html │ │ ├── index.html │ │ ├── issues.html │ │ ├── login.html │ │ ├── logs.html │ │ ├── magazines.html │ │ ├── managebooks.html │ │ ├── manageissues.html │ │ ├── manualsearch.html │ │ ├── members.html │ │ ├── opds.html │ │ ├── profile.html │ │ ├── register.html │ │ ├── response.html │ │ ├── searchresults.html │ │ ├── series.html │ │ ├── shutdown.html │ │ └── users.html │ └── legacy │ │ ├── author.html │ │ ├── base.html │ │ ├── books.html │ │ ├── config.html │ │ ├── dbupdate.html │ │ ├── editauthor.html │ │ ├── editbook.html │ │ ├── history.html │ │ ├── index.html │ │ ├── issues.html │ │ ├── logs.html │ │ ├── magazines.html │ │ ├── managebooks.html │ │ ├── manageissues.html │ │ ├── manualsearch.html │ │ ├── members.html │ │ ├── response.html │ │ ├── searchresults.html │ │ ├── series.html │ │ └── shutdown.html ├── js │ ├── adapt.js │ ├── adapt.min.js │ ├── bootbox.min.js │ ├── bootstrap-notify.js │ ├── bootstrap-notify.min.js │ ├── bootstrap.min.js │ ├── datatables.min.js │ ├── jquery-1.12.0.min.js │ ├── jquery-1.8.2.js │ ├── jquery-migrate-1.3.0.min.js │ ├── jquery.clearsearch.js │ ├── lazylibrarian-bs.js │ ├── lazylibrarian.js │ ├── libs │ │ ├── dd_belatedpng.js │ │ ├── jquery-1.6.2.js │ │ ├── jquery-1.6.2.min.js │ │ ├── jquery.dataTables.min.js │ │ ├── modernizr-1.7.min.js │ │ └── natural.js │ ├── mootools.js │ ├── mootools_more.js │ ├── mootools_tween_css3.js │ ├── natural.js │ ├── nav.js │ ├── plugins.js │ ├── question.js │ ├── script.js │ └── summernote.js └── opensearch.template ├── epubandmobi.py ├── example.monthnames.json ├── example_custom_notification.py ├── example_custom_notification.sh ├── example_ebook_convert.py ├── example_preprocessor.py ├── gsconvert.py ├── init ├── COPYING.txt ├── INSTALL.txt ├── freebsd.initd ├── lazylibrarian.default ├── lazylibrarian.desktop ├── lazylibrarian.initd ├── lazylibrarian.service └── lazylibrarian.sh ├── lazylibrarian ├── __init__.py ├── api.py ├── bookrename.py ├── bookwork.py ├── cache.py ├── calibre.py ├── classes.py ├── common.py ├── csvfile.py ├── database.py ├── dbupgrade.py ├── deluge.py ├── directparser.py ├── downloadmethods.py ├── formatter.py ├── gb.py ├── gr.py ├── grsync.py ├── images.py ├── importer.py ├── librarysync.py ├── logger.py ├── magazinescan.py ├── magnet2torrent.py ├── manualbook.py ├── notifiers │ ├── __init__.py │ ├── androidpn.py │ ├── boxcar.py │ ├── custom_notify.py │ ├── email_notify.py │ ├── growl.py │ ├── nma.py │ ├── prowl.py │ ├── pushbullet.py │ ├── pushbullet2.py │ ├── pushover.py │ ├── slack.py │ ├── telegram.py │ └── tweet.py ├── nzbget.py ├── opds.py ├── postprocess.py ├── providers.py ├── qbittorrent.py ├── resultlist.py ├── rssfeed.py ├── rtorrent.py ├── sabnzbd.py ├── searchbook.py ├── searchmag.py ├── searchrss.py ├── synology.py ├── torrentparser.py ├── transmission.py ├── unittests │ ├── test_providers.py │ ├── test_searchnzb.py │ └── test_versioncheck.py ├── utorrent.py ├── version.py ├── versioncheck.py ├── webServe.py └── webStart.py ├── lib ├── __init__.py ├── apscheduler │ ├── __init__.py │ ├── events.py │ ├── job.py │ ├── jobstores │ │ ├── __init__.py │ │ ├── base.py │ │ ├── mongodb_store.py │ │ ├── ram_store.py │ │ ├── shelve_store.py │ │ └── sqlalchemy_store.py │ ├── scheduler.py │ ├── threadpool.py │ ├── triggers │ │ ├── __init__.py │ │ ├── cron │ │ │ ├── __init__.py │ │ │ ├── expressions.py │ │ │ └── fields.py │ │ ├── interval.py │ │ └── simple.py │ └── util.py ├── bencode │ ├── BTL.py │ ├── __init__.py │ └── exceptions.py ├── bs4 │ ├── __init__.py │ ├── builder │ │ ├── __init__.py │ │ ├── _html5lib.py │ │ ├── _htmlparser.py │ │ └── _lxml.py │ ├── dammit.py │ ├── diagnose.py │ ├── element.py │ └── testing.py ├── cherrypy_cors.py ├── csv.py ├── deluge_client │ ├── __init__.py │ ├── client.py │ └── rencode.py ├── feedparser.py ├── fuzzywuzzy │ ├── StringMatcher.py │ ├── __init__.py │ ├── fuzz.py │ ├── process.py │ ├── string_processing.py │ └── utils.py ├── gntp │ ├── LICENSE │ ├── __init__.py │ ├── cli.py │ ├── config.py │ ├── core.py │ ├── errors.py │ ├── notifier.py │ ├── shim.py │ └── version.py ├── html5lib │ ├── __init__.py │ ├── _ihatexml.py │ ├── _inputstream.py │ ├── _tokenizer.py │ ├── _trie │ │ ├── __init__.py │ │ ├── _base.py │ │ ├── datrie.py │ │ └── py.py │ ├── _utils.py │ ├── constants.py │ ├── filters │ │ ├── __init__.py │ │ ├── alphabeticalattributes.py │ │ ├── base.py │ │ ├── inject_meta_charset.py │ │ ├── lint.py │ │ ├── optionaltags.py │ │ ├── sanitizer.py │ │ └── whitespace.py │ ├── html5parser.py │ ├── serializer.py │ ├── treeadapters │ │ ├── __init__.py │ │ ├── genshi.py │ │ └── sax.py │ ├── treebuilders │ │ ├── __init__.py │ │ ├── base.py │ │ ├── dom.py │ │ ├── etree.py │ │ └── etree_lxml.py │ └── treewalkers │ │ ├── __init__.py │ │ ├── base.py │ │ ├── dom.py │ │ ├── etree.py │ │ ├── etree_lxml.py │ │ └── genshi.py ├── httpagentparser.py ├── httplib2 │ ├── __init__.py │ ├── cacerts.txt │ ├── iri2uri.py │ └── socks.py ├── magic │ ├── __init__.py │ └── compat.py ├── mobi │ ├── __init__.py │ ├── lz77.py │ └── utils.py ├── oauth2 │ ├── __init__.py │ └── lazylibrarian.note ├── pynma │ ├── __init__.py │ └── pynma.py ├── pythontwitter │ └── __init__.py ├── requests │ ├── __init__.py │ ├── _internal_utils.py │ ├── adapters.py │ ├── api.py │ ├── auth.py │ ├── cacert.pem │ ├── certs.py │ ├── compat.py │ ├── cookies.py │ ├── exceptions.py │ ├── hooks.py │ ├── models.py │ ├── packages │ │ ├── __init__.py │ │ ├── chardet │ │ │ ├── __init__.py │ │ │ ├── big5freq.py │ │ │ ├── big5prober.py │ │ │ ├── chardetect.py │ │ │ ├── chardistribution.py │ │ │ ├── charsetgroupprober.py │ │ │ ├── charsetprober.py │ │ │ ├── codingstatemachine.py │ │ │ ├── compat.py │ │ │ ├── constants.py │ │ │ ├── cp949prober.py │ │ │ ├── escprober.py │ │ │ ├── escsm.py │ │ │ ├── eucjpprober.py │ │ │ ├── euckrfreq.py │ │ │ ├── euckrprober.py │ │ │ ├── euctwfreq.py │ │ │ ├── euctwprober.py │ │ │ ├── gb2312freq.py │ │ │ ├── gb2312prober.py │ │ │ ├── hebrewprober.py │ │ │ ├── jisfreq.py │ │ │ ├── jpcntx.py │ │ │ ├── langbulgarianmodel.py │ │ │ ├── langcyrillicmodel.py │ │ │ ├── langgreekmodel.py │ │ │ ├── langhebrewmodel.py │ │ │ ├── langhungarianmodel.py │ │ │ ├── langthaimodel.py │ │ │ ├── latin1prober.py │ │ │ ├── mbcharsetprober.py │ │ │ ├── mbcsgroupprober.py │ │ │ ├── mbcssm.py │ │ │ ├── sbcharsetprober.py │ │ │ ├── sbcsgroupprober.py │ │ │ ├── sjisprober.py │ │ │ ├── universaldetector.py │ │ │ └── utf8prober.py │ │ ├── idna │ │ │ ├── __init__.py │ │ │ ├── codec.py │ │ │ ├── compat.py │ │ │ ├── core.py │ │ │ ├── idnadata.py │ │ │ ├── intranges.py │ │ │ └── uts46data.py │ │ └── urllib3 │ │ │ ├── __init__.py │ │ │ ├── _collections.py │ │ │ ├── connection.py │ │ │ ├── connectionpool.py │ │ │ ├── contrib │ │ │ ├── __init__.py │ │ │ ├── appengine.py │ │ │ ├── ntlmpool.py │ │ │ ├── pyopenssl.py │ │ │ └── socks.py │ │ │ ├── exceptions.py │ │ │ ├── fields.py │ │ │ ├── filepost.py │ │ │ ├── packages │ │ │ ├── __init__.py │ │ │ ├── backports │ │ │ │ ├── __init__.py │ │ │ │ └── makefile.py │ │ │ ├── ordered_dict.py │ │ │ ├── six.py │ │ │ └── ssl_match_hostname │ │ │ │ ├── __init__.py │ │ │ │ └── _implementation.py │ │ │ ├── poolmanager.py │ │ │ ├── request.py │ │ │ ├── response.py │ │ │ └── util │ │ │ ├── __init__.py │ │ │ ├── connection.py │ │ │ ├── request.py │ │ │ ├── response.py │ │ │ ├── retry.py │ │ │ ├── ssl_.py │ │ │ ├── timeout.py │ │ │ └── url.py │ ├── sessions.py │ ├── status_codes.py │ ├── structures.py │ └── utils.py ├── rfeed.py ├── simplejson │ ├── __init__.py │ ├── _speedups.c │ ├── compat.py │ ├── decoder.py │ ├── encoder.py │ ├── ordered_dict.py │ ├── scanner.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_bigint_as_string.py │ │ ├── test_bitsize_int_as_string.py │ │ ├── test_check_circular.py │ │ ├── test_decimal.py │ │ ├── test_decode.py │ │ ├── test_default.py │ │ ├── test_dump.py │ │ ├── test_encode_basestring_ascii.py │ │ ├── test_encode_for_html.py │ │ ├── test_errors.py │ │ ├── test_fail.py │ │ ├── test_float.py │ │ ├── test_for_json.py │ │ ├── test_indent.py │ │ ├── test_item_sort_key.py │ │ ├── test_iterable.py │ │ ├── test_namedtuple.py │ │ ├── test_pass1.py │ │ ├── test_pass2.py │ │ ├── test_pass3.py │ │ ├── test_raw_json.py │ │ ├── test_recursion.py │ │ ├── test_scanstring.py │ │ ├── test_separators.py │ │ ├── test_speedups.py │ │ ├── test_str_subclass.py │ │ ├── test_subclass.py │ │ ├── test_tool.py │ │ ├── test_tuple.py │ │ └── test_unicode.py │ └── tool.py ├── six.py ├── tinytag.note ├── tinytag.py ├── unrar │ ├── __init__.py │ ├── constants.py │ ├── rarfile.py │ └── unrarlib.py ├── webencodings │ ├── __init__.py │ ├── labels.py │ ├── mklabels.py │ ├── tests.py │ └── x_user_defined.py └── zipfile.py ├── lib3 ├── __init__.py ├── bs4 │ ├── __init__.py │ ├── builder │ │ ├── __init__.py │ │ ├── _html5lib.py │ │ ├── _htmlparser.py │ │ └── _lxml.py │ ├── dammit.py │ ├── diagnose.py │ ├── element.py │ └── testing.py ├── csv.py ├── feedparser.py ├── httplib2 │ ├── __init__.py │ ├── cacerts.txt │ └── iri2uri.py ├── sgmllib.py └── zipfile.py └── mako ├── __init__.py ├── _ast_util.py ├── ast.py ├── cache.py ├── cmd.py ├── codegen.py ├── compat.py ├── exceptions.py ├── ext ├── __init__.py ├── autohandler.py ├── babelplugin.py ├── beaker_cache.py ├── extract.py ├── linguaplugin.py ├── preprocessors.py ├── pygmentplugin.py └── turbogears.py ├── filters.py ├── lexer.py ├── lookup.py ├── parsetree.py ├── pygen.py ├── pyparser.py ├── runtime.py ├── template.py └── util.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Lazy User Related # 2 | ###################### 3 | cache/* 4 | cache.db* 5 | config.ini 6 | Logs/* 7 | lazylibrarian.db* 8 | version.txt 9 | *.log 10 | *.AuthorCache/* 11 | *.ProviderCache/* 12 | 13 | # Bookstrap related # 14 | ####################### 15 | #data/README.md 16 | #data/css/bookstrap.css 17 | #data/images/cache/ 18 | #data/images/ll.ico 19 | #data/interfaces/bookstrap/ 20 | #data/js/bootbox.min.js 21 | #data/js/bootstrap-notify.js 22 | #data/js/bootstrap-notify.min.js 23 | #data/js/lazylibrarian-bs.js 24 | 25 | # Compiled source # 26 | ###################### 27 | *.py[co] 28 | 29 | # Prebuilt packages # 30 | ###################### 31 | packages 32 | *.deb 33 | *.rpm 34 | 35 | # IDE specific # 36 | ###################### 37 | *.bak 38 | *.tmp 39 | *.wpr 40 | *.project 41 | *.cproject 42 | *.tmproj 43 | *.tmproject 44 | 45 | # OS generated files # 46 | ###################### 47 | .Spotlight-V100 48 | .Trashes 49 | .DS_Store 50 | desktop.ini 51 | ehthumbs.db 52 | Thumbs.db 53 | .directory 54 | *~ 55 | *.db 56 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | To help with identifying and fixing issues, please include as much information as possible, including: 2 | ### LazyLibrarian version number (at the bottom of config page) 3 | ### Operating system used (windows, mac, linux, NAS type) 4 | ### Interface in use (default, bookstrap) 5 | ### Which api (Goodreads, GoogleBooks, both) 6 | ### Source of your LazyLibrarian installation (git, zip file, 3rd party package) 7 | ### Relevant debug log with api keys and any passwords redacted 8 | 9 | Please note - usually a single line of log is not sufficient. The lines just before the error occurs can give useful context and greatly assist with debugging. 10 | 11 | ### There is a built-in debug log creator on the logs page which makes it easy to provide this information 12 | * To use it, first go to the log page and make sure debug logging is OFF 13 | * Now press the "Start debug log" button 14 | * Go and do whatever you need to recreate the error 15 | * Go back to the log page and press "Save debug log" 16 | * You can now turn debug logging off again if you want 17 | * The saved log file will be found in your lazylibrarian log directory called debug.zip 18 | * It will contain all lines logged since you pressed "Start debug log" with any passwords and api keys removed 19 | * Attach the zip file to your bug report. 20 | -------------------------------------------------------------------------------- /LazyLibrarian.app/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSUIElement 6 | 1 7 | CFBundleAllowMixedLocalizations 8 | 9 | CFBundleDevelopmentRegion 10 | English 11 | CFBundleExecutable 12 | applet 13 | CFBundleIconFile 14 | applet 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | MovieManager 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | aplt 23 | LSMinimumSystemVersionByArchitecture 24 | 25 | x86_64 26 | 10.6 27 | 28 | LSRequiresCarbon 29 | 30 | WindowState 31 | 32 | dividerCollapsed 33 | 34 | eventLogLevel 35 | -1 36 | name 37 | ScriptWindowState 38 | positionOfDivider 39 | 333 40 | savedFrame 41 | 85 111 602 597 0 0 1280 778 42 | selectedTabView 43 | event log 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /LazyLibrarian.app/Contents/MacOS/applet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/LazyLibrarian.app/Contents/MacOS/applet -------------------------------------------------------------------------------- /LazyLibrarian.app/Contents/PkgInfo: -------------------------------------------------------------------------------- 1 | APPLaplt -------------------------------------------------------------------------------- /LazyLibrarian.app/Contents/Resources/Scripts/main.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/LazyLibrarian.app/Contents/Resources/Scripts/main.scpt -------------------------------------------------------------------------------- /LazyLibrarian.app/Contents/Resources/applet.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/LazyLibrarian.app/Contents/Resources/applet.icns -------------------------------------------------------------------------------- /LazyLibrarian.app/Contents/Resources/applet.rsrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/LazyLibrarian.app/Contents/Resources/applet.rsrc -------------------------------------------------------------------------------- /LazyLibrarian.app/Contents/Resources/description.rtfd/TXT.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf320 2 | {\fonttbl} 3 | {\colortbl;\red255\green255\blue255;} 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## LazyLibrarian 2 | LazyLibrarian is a program to follow authors and grab metadata for all your digital reading needs. 3 | It uses a combination of [Goodreads](https://www.goodreads.com/) [Librarything](https://www.librarything.com/) and optionally [GoogleBooks](https://www.googleapis.com/books/v1/) as sources for author info and book info. License: GNU GPL v3 4 | 5 | ## 6 | 7 | Current source repo is [LazyLibrarian](https://gitlab.com/LazyLibrarian/LazyLibrarian.git) 8 | 9 | All open issues have been moved over to [LazyLibrarian Issues](https://gitlab.com/LazyLibrarian/LazyLibrarian/issues) 10 | Please open any new issues on the new repo as the old one is no longer maintained, thanks 11 | -------------------------------------------------------------------------------- /UNITTESTING.md: -------------------------------------------------------------------------------- 1 | # 2 | # Dec 2013 3 | # 4 | #starting to introduce some form of BDD/TDD testing using the simple unittest tools 5 | 6 | I am by no means an exprt on TDD/BDD. My aim is to start simple. 7 | 8 | Inspiration is Uncle Bob - The Clean Coder and Clean Code books (Robert Martin). I had the pleasure of seeing him at work in the office in Dublin, and it was amazing. Simple genius always is. 9 | 10 | So my attempts will revolve around the "Boy Scout Rule" - Code must be no worse after I touch it. 11 | 12 | To achieve this I hope to 13 | - create unit test(s) around the function I'm changing 14 | - create new test(s) for the change required [these will be broken until code added] 15 | - refactor the area of change into logical smaller functions 16 | - make the change and check in once all tests pass. 17 | 18 | 19 | 20 | 21 | # 22 | #Requires 23 | # 24 | unittest for python 25 | 26 | sudo apt-get install python-setuptools 27 | 28 | 29 | # 30 | #Execution 31 | #- run from the Lazylibrarian root directory (directory where LazyLibrarian.py exists) 32 | python -m unittest discover lazylibrarian/unittests/ 33 | 34 | expected output looks as follows (the two periods indicate 2 tests run) 35 | .. 36 | ---------------------------------------------------------------------- 37 | Ran 2 tests in 0.001s 38 | 39 | OK 40 | -------------------------------------------------------------------------------- /cherrypy/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2004-2011, CherryPy Team (team@cherrypy.org) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | * Neither the name of the CherryPy Team nor the names of its contributors 13 | may be used to endorse or promote products derived from this software 14 | without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /cherrypy/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/cherrypy/favicon.ico -------------------------------------------------------------------------------- /cherrypy/lazylibrarian.note: -------------------------------------------------------------------------------- 1 | This is v3.6.0 of cherrypy slightly modified for lazylibrarian. 2 | Later versions of cherrypy need additional libaries that we can't 3 | be sure are installed on all systems (eg NAS devices) 4 | 5 | This version has a small change to _cpreqbody.py line 1006 6 | key = key.encode('ISO-8859-1') 7 | changed to also allow 8 | key = key.encode('utf-8') 9 | as not all entries in POST forms are encodable in latin-1 10 | eg accented magazine titles. 11 | Without this change, saving Lazylibrarian config page can cause an exception. 12 | There is probably a better way of doing this... 13 | 14 | Also in _cpcompat.py and lib/cpstats.py we import a local copy of simplejson 15 | as we cannot be sure all target devices have it installed, or have a new-ish version. 16 | NOTE - we do not currently use lib/cpstats.py 17 | -------------------------------------------------------------------------------- /cherrypy/lib/http.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | warnings.warn('cherrypy.lib.http has been deprecated and will be removed ' 3 | 'in CherryPy 3.3 use cherrypy.lib.httputil instead.', 4 | DeprecationWarning) 5 | 6 | from cherrypy.lib.httputil import * 7 | -------------------------------------------------------------------------------- /cherrypy/lib/locking.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | 4 | class NeverExpires(object): 5 | def expired(self): 6 | return False 7 | 8 | 9 | class Timer(object): 10 | """ 11 | A simple timer that will indicate when an expiration time has passed. 12 | """ 13 | def __init__(self, expiration): 14 | "Create a timer that expires at `expiration` (UTC datetime)" 15 | self.expiration = expiration 16 | 17 | @classmethod 18 | def after(cls, elapsed): 19 | """ 20 | Return a timer that will expire after `elapsed` passes. 21 | """ 22 | return cls(datetime.datetime.utcnow() + elapsed) 23 | 24 | def expired(self): 25 | return datetime.datetime.utcnow() >= self.expiration 26 | 27 | 28 | class LockTimeout(Exception): 29 | "An exception when a lock could not be acquired before a timeout period" 30 | 31 | 32 | class LockChecker(object): 33 | """ 34 | Keep track of the time and detect if a timeout has expired 35 | """ 36 | def __init__(self, session_id, timeout): 37 | self.session_id = session_id 38 | if timeout: 39 | self.timer = Timer.after(timeout) 40 | else: 41 | self.timer = NeverExpires() 42 | 43 | def expired(self): 44 | if self.timer.expired(): 45 | raise LockTimeout( 46 | "Timeout acquiring lock for %(session_id)s" % vars(self)) 47 | return False 48 | -------------------------------------------------------------------------------- /cherrypy/lib/xmlrpcutil.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import cherrypy 4 | from cherrypy._cpcompat import ntob 5 | 6 | 7 | def get_xmlrpclib(): 8 | try: 9 | import xmlrpc.client as x 10 | except ImportError: 11 | import xmlrpclib as x 12 | return x 13 | 14 | 15 | def process_body(): 16 | """Return (params, method) from request body.""" 17 | try: 18 | return get_xmlrpclib().loads(cherrypy.request.body.read()) 19 | except Exception: 20 | return ('ERROR PARAMS', ), 'ERRORMETHOD' 21 | 22 | 23 | def patched_path(path): 24 | """Return 'path', doctored for RPC.""" 25 | if not path.endswith('/'): 26 | path += '/' 27 | if path.startswith('/RPC2/'): 28 | # strip the first /rpc2 29 | path = path[5:] 30 | return path 31 | 32 | 33 | def _set_response(body): 34 | # The XML-RPC spec (http://www.xmlrpc.com/spec) says: 35 | # "Unless there's a lower-level error, always return 200 OK." 36 | # Since Python's xmlrpclib interprets a non-200 response 37 | # as a "Protocol Error", we'll just return 200 every time. 38 | response = cherrypy.response 39 | response.status = '200 OK' 40 | response.body = ntob(body, 'utf-8') 41 | response.headers['Content-Type'] = 'text/xml' 42 | response.headers['Content-Length'] = len(body) 43 | 44 | 45 | def respond(body, encoding='utf-8', allow_none=0): 46 | xmlrpclib = get_xmlrpclib() 47 | if not isinstance(body, xmlrpclib.Fault): 48 | body = (body,) 49 | _set_response(xmlrpclib.dumps(body, methodresponse=1, 50 | encoding=encoding, 51 | allow_none=allow_none)) 52 | 53 | 54 | def on_error(*args, **kwargs): 55 | body = str(sys.exc_info()[1]) 56 | xmlrpclib = get_xmlrpclib() 57 | _set_response(xmlrpclib.dumps(xmlrpclib.Fault(1, body))) 58 | -------------------------------------------------------------------------------- /cherrypy/process/__init__.py: -------------------------------------------------------------------------------- 1 | """Site container for an HTTP server. 2 | 3 | A Web Site Process Bus object is used to connect applications, servers, 4 | and frameworks with site-wide services such as daemonization, process 5 | reload, signal handling, drop privileges, PID file management, logging 6 | for all of these, and many more. 7 | 8 | The 'plugins' module defines a few abstract and concrete services for 9 | use with the bus. Some use tool-specific channels; see the documentation 10 | for each class. 11 | """ 12 | 13 | from cherrypy.process.wspbus import bus 14 | from cherrypy.process import plugins, servers 15 | -------------------------------------------------------------------------------- /cherrypy/scaffold/__init__.py: -------------------------------------------------------------------------------- 1 | """, a CherryPy application. 2 | 3 | Use this as a base for creating new CherryPy applications. When you want 4 | to make a new app, copy and paste this folder to some other location 5 | (maybe site-packages) and rename it to the name of your project, 6 | then tweak as desired. 7 | 8 | Even before any tweaking, this should serve a few demonstration pages. 9 | Change to this directory and run: 10 | 11 | ../cherryd -c site.conf 12 | 13 | """ 14 | 15 | import cherrypy 16 | from cherrypy import tools, url 17 | 18 | import os 19 | local_dir = os.path.join(os.getcwd(), os.path.dirname(__file__)) 20 | 21 | 22 | class Root: 23 | 24 | _cp_config = {'tools.log_tracebacks.on': True, 25 | } 26 | 27 | def index(self): 28 | return """ 29 | Try some other path, 30 | or a default path.
31 | Or, just look at the pretty picture:
32 | 33 | """ % (url("other"), url("else"), 34 | url("files/made_with_cherrypy_small.png")) 35 | index.exposed = True 36 | 37 | def default(self, *args, **kwargs): 38 | return "args: %s kwargs: %s" % (args, kwargs) 39 | default.exposed = True 40 | 41 | def other(self, a=2, b='bananas', c=None): 42 | cherrypy.response.headers['Content-Type'] = 'text/plain' 43 | if c is None: 44 | return "Have %d %s." % (int(a), b) 45 | else: 46 | return "Have %d %s, %s." % (int(a), b, c) 47 | other.exposed = True 48 | 49 | files = cherrypy.tools.staticdir.handler( 50 | section="/files", 51 | dir=os.path.join(local_dir, "static"), 52 | # Ignore .php files, etc. 53 | match=r'\.(css|gif|html?|ico|jpe?g|js|png|swf|xml)$', 54 | ) 55 | 56 | 57 | root = Root() 58 | 59 | # Uncomment the following to use your own favicon instead of CP's default. 60 | #favicon_path = os.path.join(local_dir, "favicon.ico") 61 | #root.favicon_ico = tools.staticfile.handler(filename=favicon_path) 62 | -------------------------------------------------------------------------------- /cherrypy/scaffold/apache-fcgi.conf: -------------------------------------------------------------------------------- 1 | # Apache2 server conf file for using CherryPy with mod_fcgid. 2 | 3 | # This doesn't have to be "C:/", but it has to be a directory somewhere, and 4 | # MUST match the directory used in the FastCgiExternalServer directive, below. 5 | DocumentRoot "C:/" 6 | 7 | ServerName 127.0.0.1 8 | Listen 80 9 | LoadModule fastcgi_module modules/mod_fastcgi.dll 10 | LoadModule rewrite_module modules/mod_rewrite.so 11 | 12 | Options ExecCGI 13 | SetHandler fastcgi-script 14 | RewriteEngine On 15 | # Send requests for any URI to our fastcgi handler. 16 | RewriteRule ^(.*)$ /fastcgi.pyc [L] 17 | 18 | # The FastCgiExternalServer directive defines filename as an external FastCGI application. 19 | # If filename does not begin with a slash (/) then it is assumed to be relative to the ServerRoot. 20 | # The filename does not have to exist in the local filesystem. URIs that Apache resolves to this 21 | # filename will be handled by this external FastCGI application. 22 | FastCgiExternalServer "C:/fastcgi.pyc" -host 127.0.0.1:8088 -------------------------------------------------------------------------------- /cherrypy/scaffold/example.conf: -------------------------------------------------------------------------------- 1 | [/] 2 | log.error_file: "error.log" 3 | log.access_file: "access.log" -------------------------------------------------------------------------------- /cherrypy/scaffold/site.conf: -------------------------------------------------------------------------------- 1 | [global] 2 | # Uncomment this when you're done developing 3 | #environment: "production" 4 | 5 | server.socket_host: "0.0.0.0" 6 | server.socket_port: 8088 7 | 8 | # Uncomment the following lines to run on HTTPS at the same time 9 | #server.2.socket_host: "0.0.0.0" 10 | #server.2.socket_port: 8433 11 | #server.2.ssl_certificate: '../test/test.pem' 12 | #server.2.ssl_private_key: '../test/test.pem' 13 | 14 | tree.myapp: cherrypy.Application(scaffold.root, "/", "example.conf") 15 | -------------------------------------------------------------------------------- /cherrypy/scaffold/static/made_with_cherrypy_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/cherrypy/scaffold/static/made_with_cherrypy_small.png -------------------------------------------------------------------------------- /cherrypy/wsgiserver/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['HTTPRequest', 'HTTPConnection', 'HTTPServer', 2 | 'SizeCheckWrapper', 'KnownLengthRFile', 'ChunkedRFile', 3 | 'MaxSizeExceeded', 'NoSSLError', 'FatalSSLAlert', 4 | 'WorkerThread', 'ThreadPool', 'SSLAdapter', 5 | 'CherryPyWSGIServer', 6 | 'Gateway', 'WSGIGateway', 'WSGIGateway_10', 'WSGIGateway_u0', 7 | 'WSGIPathInfoDispatcher', 'get_ssl_adapter_class'] 8 | 9 | import sys 10 | if sys.version_info < (3, 0): 11 | from wsgiserver2 import * 12 | else: 13 | # Le sigh. Boo for backward-incompatible syntax. 14 | exec('from .wsgiserver3 import *') 15 | -------------------------------------------------------------------------------- /data/README.md: -------------------------------------------------------------------------------- 1 | ### Bookstrap Theme (Interface) for LazyLibrarian 2 | 3 | Based on bootstrap 3. Optimised for responsive design from mobile to desktop. 4 | 5 | ## Usage 6 | 7 | Files include styles and javascript additions to the default interface. Does not intefere, change or overwite any of the default interface. 8 | 9 | Clone this into your LazyLibrarian data path and you should find "bookstrap" appears in your config as an additional interface / theme. 10 | 11 | If you'd like to change the default theme you can edit the base.html file and change the "slate" css file to another name you can find here: [MaxCDN Bootswath Themes](https://www.bootstrapcdn.com/bootswatch/) 12 | 13 | In fact if you have anyother bootstrap 3 based theme you could replace it for your own. 14 | 15 | ## Known issues 16 | 17 | As my focus is primarily on books the magazine section is somewhat under developed at this stage, but is catching up fast. 18 | 19 | ## Screenshots 20 | 21 | Using the initial "flatly" bootswatch. 22 | 23 | ![screenshot](http://i.imgur.com/tYGhjs7.png) 24 | 25 | ![screenshot](http://i.imgur.com/7tp8Vtj.png) 26 | 27 | ![screenshot](http://i.imgur.com/6RsRPTY.png) 28 | 29 | ![screenshot](http://i.imgur.com/HhzdDnD.png) 30 | 31 | -------------------------------------------------------------------------------- /data/css/bookstrap.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Bookstrap Styles 4 | */ 5 | 6 | #authorart_menu img { 7 | box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); 8 | margin-right: 15px; 9 | border: 1px solid grey; 10 | padding: 5px; 11 | background-color: white; 12 | margin-top: 20px; 13 | margin-bottom: 20px; 14 | } 15 | #subnav { 16 | /* position: fixed; 17 | top: 60px; 18 | z-index: 1030; */ 19 | position: relative; 20 | float: bottom; 21 | width: 100%; 22 | padding-top: 10px; 23 | padding-bottom: 5px; 24 | } 25 | #headercontainer { 26 | /* position: fixed; 27 | top: 60px; 28 | z-index: 1030; */ 29 | position: relative; 30 | float: top; 31 | width: 100%; 32 | padding-top: 10px; 33 | } 34 | 35 | .bookcover-sm { 36 | width: 100px; 37 | margin: auto auto; 38 | } 39 | .bookcover-xs { 40 | width: 50px; 41 | margin: auto auto; 42 | } 43 | .table-responsive { 44 | border: 0; 45 | } 46 | 47 | #subhead_container .form-group { 48 | margin-bottom: 0; 49 | } 50 | .progress { 51 | height: auto; 52 | } 53 | .progress .progress-bar { 54 | font-size: inherit; 55 | line-height: inherit; 56 | min-height: 10px; 57 | } 58 | 59 | body.modal-open-noscroll { 60 | margin-right: 0!important; 61 | overflow: hidden; 62 | } 63 | .modal-open-noscroll .navbar-fixed-top, .modal-open .navbar-fixed-bottom { 64 | margin-right: 0!important; 65 | } 66 | select { 67 | font-family: 'FontAwesome', 'sans-serif'; 68 | } 69 | -------------------------------------------------------------------------------- /data/css/ipad_landscape.css: -------------------------------------------------------------------------------- 1 | @media (max-width:1024px !important;) 2 | 3 | html {max-width:1024px !important; min-width:768px !important;} 4 | body {} 5 | 6 | 7 | #nav {} 8 | #searchbar {} 9 | 10 | table.display {width:100% !important; max-width:768px !important;} 11 | 12 | .dataTables_length {} 13 | .dataTables_filter {} 14 | .dataTables_info {display:none;} 15 | 16 | /* Main Page */ 17 | 18 | #author_table { } 19 | table#author_table {} 20 | table#author_table th#authorname {min-width:20px !important;} 21 | table#author_table th#bookname { min-width:50px; } 22 | table#author_table th#status { min-width:20px; } 23 | table#author_table th#have { min-width:20px !important; } 24 | table#author_table th#date { display:none; } 25 | table#author_table th#stars, td#stars { display:none; } 26 | table#author_table th#have { text-align: left; width:20px !important;} 27 | table#author_table td#authorname { min-width:20px !important; vertical-align: middle; text-align: left; } 28 | table#author_table td#bookname { min-width:20px; } 29 | table#author_table td#status { min-width:20px; } 30 | 31 | /* Books page */ 32 | table#book_table {background-color: white; margin-left:5px; margin-right:5px; max-width:100%; width:99%; } 33 | table#book_table th#select, td#select { } 34 | table#book_table th#bookart, td#bookart { } 35 | table#book_table th#bookname, td#bookname { } 36 | table#book_table th#authorname, td#authorname { } 37 | table#book_table th#status, td#status { } 38 | table#book_table th#date, td#date { display:none; } 39 | table#book_table th#series, td#series { } 40 | table#book_table th#seriesNum, td#seriesNum { vertical-align: middle; } 41 | table#book_table th#language, td#language { } 42 | table#book_table th#stars, td#stars { display:none; } 43 | 44 | 45 | /* Log */ 46 | table#log_table { background-color: white; margin-left:5px; margin-right:5px; max-width:100%; width:99%;} 47 | table#log_table th#timestamp { text-align: left; width: 150px; } 48 | table#log_table th#level { } 49 | table#log_table th#message { text-align: left; min-width: 300px; } 50 | table#log_table td#timestamp { text-align: left; min-width: 150px; } 51 | table#log_table td#level { } 52 | table#log_table td#message { text-align: left; min-width: 300px; } 53 | -------------------------------------------------------------------------------- /data/css/ipad_portrait.css: -------------------------------------------------------------------------------- 1 | @media (max-width:768px !important;) 2 | 3 | html {max-width:768px !important; min-width:640px !important;} 4 | body {} 5 | 6 | 7 | #nav {min-width:200px !important; } 8 | #searchbar {} 9 | 10 | table.display {width:100% !important; max-width:640px !important;} 11 | 12 | .dataTables_length {} 13 | .dataTables_filter {} 14 | .dataTables_info {display:none;} 15 | 16 | 17 | #author_table { } 18 | table#author_table {} 19 | table#author_table th#authorname {min-width:20px !important;} 20 | table#author_table th#bookname, td#bookname { display:none;} 21 | table#author_table th#status { min-width:20px; } 22 | table#author_table th#have, td#have { min-width:20px !important; } 23 | 24 | table#author_table th#date, td#date { display:none; } 25 | table#author_table th#stars, td#stars { display:none; } 26 | 27 | table#author_table td#authorname { min-width:20px !important; vertical-align: middle; text-align: left; } 28 | table#author_table td#status { min-width:20px; } 29 | 30 | /* Books page */ 31 | table#book_table { } 32 | table#book_table th#select, td#select { } 33 | table#book_table th#bookart, td#bookart { display:none; } 34 | table#book_table th#bookname, td#bookname { } 35 | table#book_table th#authorname, td#authorname { } 36 | table#book_table th#status, td#status { } 37 | table#book_table th#date, td#date { display:none; } 38 | table#book_table th#language, td#language { display:none; } 39 | table#book_table th#stars, td#stars { display:none; } 40 | table#book_table th#seriesNum, td#seriesNum { display:none; } 41 | table#book_table th#series, td#series { } 42 | 43 | 44 | /* Log */ 45 | table#log_table { background-color: white; margin-left:5px; margin-right:5px; max-width:100%; width:99%; } 46 | table#log_table th#timestamp { text-align: left; width: 150px; } 47 | table#log_table th#level { } 48 | table#log_table th#message { text-align: left; min-width: 100px; } 49 | table#log_table td#timestamp { text-align: left; min-width: 150px; } 50 | table#log_table td#level { } 51 | table#log_table td#message { text-align: left; min-width: 100px; } 52 | -------------------------------------------------------------------------------- /data/css/iphone4_portrait.css: -------------------------------------------------------------------------------- 1 | @media (max-width:640px !important; min-width:640px !important;) 2 | html {max-width:640px !important; min-width:320px !important;} 3 | body {} 4 | 5 | 6 | #nav { !important; min-width:200px !important; } 7 | #searchbar {} 8 | #searchbox {width:130px; margin-right:0px;} 9 | div#searchbar { margin-right:5px; } 10 | 11 | 12 | table.display {width:100% !important; } 13 | 14 | .dataTables_length {} 15 | .dataTables_filter {} 16 | .dataTables_info {display:none;} 17 | 18 | 19 | #author_table { } 20 | table#author_table {} 21 | table#author_table th#authorname {min-width:20px !important;} 22 | table#author_table th#bookname { display:none;} 23 | table#author_table th#status { min-width:20px; } 24 | table#author_table th#have { min-width:20px !important; } 25 | 26 | table#author_table th#date, td#date { display:none; } 27 | table#author_table th#stars, td#stars { display:none; } 28 | 29 | table#author_table th#have { text-align: left; width:20px !important;} 30 | table#author_table td#authorname { min-width:20px !important; vertical-align: middle; text-align: left; } 31 | table#author_table td#bookname { display:none; } 32 | table#author_table td#status { min-width:20px; } 33 | table#author_table th#series, td#series { display:none; } 34 | table#author_table th#seriesNum, td#seriesNum { display:none; } 35 | 36 | /* Books page */ 37 | table#book_table { } 38 | table#book_table th#select, td#select { } 39 | table#book_table th#bookart, td#bookart { display:none; } 40 | table#book_table th#bookname, td#bookname { } 41 | table#book_table th#authorname, td#authorname { } 42 | table#book_table th#status, td#status { } 43 | table#book_table th#date, td#date { display:none; } 44 | table#book_table th#series, td#series { display:none; } 45 | table#book_table th#language, td#language { display:none; } 46 | table#book_table th#stars, td#stars { display:none; } 47 | table#book_table th#seriesNum, td#seriesNum { display:none; } 48 | 49 | /* Log */ 50 | table#log_table { background-color: white; margin-left:5px; margin-right:5px; max-width:100%; width:99%; } 51 | table#log_table th#timestamp, td#timestamp { display:none; } 52 | table#log_table th#level, td#level { } 53 | table#log_table th#message, td#message { text-align: left; } 54 | -------------------------------------------------------------------------------- /data/css/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/css/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /data/css/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/css/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /data/css/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/css/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /data/css/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/css/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /data/css/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/css/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /data/css/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/css/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /data/css/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/css/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /data/css/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/css/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /data/images/0-stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/0-stars.png -------------------------------------------------------------------------------- /data/images/1-stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/1-stars.png -------------------------------------------------------------------------------- /data/images/2-stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/2-stars.png -------------------------------------------------------------------------------- /data/images/3-stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/3-stars.png -------------------------------------------------------------------------------- /data/images/4-stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/4-stars.png -------------------------------------------------------------------------------- /data/images/5-stars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/5-stars.png -------------------------------------------------------------------------------- /data/images/back_disabled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/back_disabled.jpg -------------------------------------------------------------------------------- /data/images/back_enabled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/back_enabled.jpg -------------------------------------------------------------------------------- /data/images/checkmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/checkmark.png -------------------------------------------------------------------------------- /data/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/favicon.ico -------------------------------------------------------------------------------- /data/images/forward_disabled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/forward_disabled.jpg -------------------------------------------------------------------------------- /data/images/forward_enabled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/forward_enabled.jpg -------------------------------------------------------------------------------- /data/images/icon_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/icon_search.png -------------------------------------------------------------------------------- /data/images/lazylibrarian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/lazylibrarian.png -------------------------------------------------------------------------------- /data/images/ll.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/ll.ico -------------------------------------------------------------------------------- /data/images/ll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/ll.png -------------------------------------------------------------------------------- /data/images/ll128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/ll128.png -------------------------------------------------------------------------------- /data/images/ll16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/ll16.png -------------------------------------------------------------------------------- /data/images/ll192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/ll192.png -------------------------------------------------------------------------------- /data/images/ll256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/ll256.png -------------------------------------------------------------------------------- /data/images/ll32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/ll32.png -------------------------------------------------------------------------------- /data/images/ll48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/ll48.png -------------------------------------------------------------------------------- /data/images/ll512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/ll512.png -------------------------------------------------------------------------------- /data/images/ll64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/ll64.png -------------------------------------------------------------------------------- /data/images/loader_black.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/loader_black.gif -------------------------------------------------------------------------------- /data/images/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LazyLibrarian", 3 | "short_name": "LazyLibrarian", 4 | "icons": [ 5 | { "src": "images/ll32.png", "sizes": "32x32", "type": "image/png" }, 6 | { "src": "images/ll48.png", "sizes": "48x48", "type": "image/png" }, 7 | { "src": "images/ll64.png", "sizes": "64x64", "type": "image/png" }, 8 | { "src": "images/ll128.png", "sizes": "128x128", "type": "image/png" }, 9 | { "src": "images/ll192.png", "sizes": "192x192", "type": "image/png" }, 10 | { "src": "images/ll256.png", "sizes": "256x256", "type": "image/png" }, 11 | { "src": "images/ll512.png", "sizes": "512x512", "type": "image/png" } ], 12 | "theme_color": "#272727", 13 | "background_color": "#272727", 14 | "display": "standalone", 15 | "orientation": "natural" 16 | } 17 | -------------------------------------------------------------------------------- /data/images/nav/auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nav/auth.png -------------------------------------------------------------------------------- /data/images/nav/blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nav/blank.png -------------------------------------------------------------------------------- /data/images/nav/book.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nav/book.png -------------------------------------------------------------------------------- /data/images/nav/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nav/config.png -------------------------------------------------------------------------------- /data/images/nav/hist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nav/hist.png -------------------------------------------------------------------------------- /data/images/nav/logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nav/logs.png -------------------------------------------------------------------------------- /data/images/nav/mags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nav/mags.png -------------------------------------------------------------------------------- /data/images/nav/manage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nav/manage.png -------------------------------------------------------------------------------- /data/images/nav/series.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nav/series.png -------------------------------------------------------------------------------- /data/images/nocover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nocover.jpg -------------------------------------------------------------------------------- /data/images/nocover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nocover.png -------------------------------------------------------------------------------- /data/images/nophoto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nophoto.png -------------------------------------------------------------------------------- /data/images/nostar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/nostar.png -------------------------------------------------------------------------------- /data/images/restart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/restart.png -------------------------------------------------------------------------------- /data/images/shutdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/shutdown.png -------------------------------------------------------------------------------- /data/images/sort_asc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/sort_asc.png -------------------------------------------------------------------------------- /data/images/sort_asc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/sort_asc_disabled.png -------------------------------------------------------------------------------- /data/images/sort_both.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/sort_both.png -------------------------------------------------------------------------------- /data/images/sort_desc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/sort_desc.png -------------------------------------------------------------------------------- /data/images/sort_desc_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/sort_desc_disabled.png -------------------------------------------------------------------------------- /data/images/sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/sprite.png -------------------------------------------------------------------------------- /data/images/sprite1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/sprite1.png -------------------------------------------------------------------------------- /data/images/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/data/images/star.png -------------------------------------------------------------------------------- /data/interfaces/bookstrap/choosetype.html: -------------------------------------------------------------------------------- 1 | <%inherit file="base.html"/> 2 | <%! 3 | import lazylibrarian 4 | %> 5 | <%def name="headIncludes()"> 6 | 7 | <%def name="body()"> 8 |
9 |
10 | 11 | 12 | <%def name="headIncludes()"> 13 | 14 | <%def name="javascriptIncludes()"> 15 | 58 | 59 | -------------------------------------------------------------------------------- /data/interfaces/bookstrap/dbupdate.html: -------------------------------------------------------------------------------- 1 | <%inherit file="base.html"/> 2 | <%! 3 | import lazylibrarian 4 | %> 5 | <%def name="headIncludes()"> 6 | 7 | <%def name="body()"> 8 |

 

9 |
10 |

${message}

11 |

${lazylibrarian.UPDATE_MSG}

12 |
13 | 14 | <%def name="javascriptIncludes()"> 15 | 26 | 27 | -------------------------------------------------------------------------------- /data/interfaces/bookstrap/dlresult.html: -------------------------------------------------------------------------------- 1 | <%inherit file="base.html"/> 2 | <%! 3 | import lazylibrarian 4 | %> 5 | <%def name="headIncludes()"> 6 | 7 | <%def name="body()"> 8 |
9 |
10 | 11 | 12 | <%def name="headIncludes()"> 13 | 14 | <%def name="javascriptIncludes()"> 15 | 49 | 50 | -------------------------------------------------------------------------------- /data/interfaces/bookstrap/opds.html: -------------------------------------------------------------------------------- 1 | <%! 2 | import lazylibrarian 3 | %> 4 | 9 | ${opds['title']} 10 | ${opds['id']} 11 | ${opds['updated']} 12 | 13 | LazyLibrarian Server 14 | https://${lazylibrarian.CONFIG['GIT_HOST']}/${lazylibrarian.CONFIG['GIT_USER']}/${lazylibrarian.CONFIG['GIT_REPO']} 15 | 16 | %for link in opds['links']: 17 | <% 18 | linktitle = '' 19 | if 'title' in link: 20 | linktitle = ' title="%s"' % link['title'] 21 | %> 22 | 23 | %endfor 24 | %for entry in opds['entries']: 25 | 26 | ${entry['title']} 27 | ${entry['id']} 28 | %if 'author' in entry and entry['author']: 29 | 30 | ${entry['author']} 31 | 32 | %endif 33 | ${entry['updated']} 34 | ${entry['content']} 35 | %if entry['rel'] == 'file': 36 | 37 | %else: 38 | % if entry['rel'] == 'multi': 39 | ${entry['type']} 40 | %else: 41 | 42 | %endif 43 | %endif 44 | %if 'thumbnail' in entry and entry['thumbnail']: 45 | 46 | %endif 47 | %if 'image' in entry and entry['image']: 48 | 49 | %endif 50 | 51 | %endfor 52 | 53 | -------------------------------------------------------------------------------- /data/interfaces/bookstrap/response.html: -------------------------------------------------------------------------------- 1 | <%inherit file="base.html"/> 2 | <%! 3 | import lazylibrarian 4 | %> 5 | <%def name="headIncludes()"> 6 | 7 | <%def name="body()"> 8 |
9 |
10 | 11 | 12 | <%def name="headIncludes()"> 13 | 14 | <%def name="javascriptIncludes()"> 15 | 47 | 48 | -------------------------------------------------------------------------------- /data/interfaces/bookstrap/shutdown.html: -------------------------------------------------------------------------------- 1 | <%inherit file="base.html"/> 2 | <%def name="headIncludes()"> 3 | 4 | <%def name="body()"> 5 |

 

6 |
7 |

${title}

8 | %if timer == 0: 9 |

${prefix} ${message}

10 | %else: 11 |

  ${prefix} ${message}

12 | %endif 13 |

 

14 |
15 | 16 | <%def name="javascriptIncludes()"> 17 | 31 | 32 | -------------------------------------------------------------------------------- /data/interfaces/legacy/dbupdate.html: -------------------------------------------------------------------------------- 1 | <%inherit file="base.html"/> 2 | <%! 3 | import lazylibrarian 4 | %> 5 | <%def name="headIncludes()"> 6 | 7 | 8 | <%def name="body()"> 9 |
10 |
11 |

${message}

12 |

${lazylibrarian.UPDATE_MSG}

13 |
14 |
15 | 16 | -------------------------------------------------------------------------------- /data/interfaces/legacy/editauthor.html: -------------------------------------------------------------------------------- 1 | <%inherit file="base.html"/> 2 | <%! 3 | import lazylibrarian 4 | %> 5 | <%def name="headerIncludes()"> 6 |
7 |
8 | 9 | <%def name="body()"> 10 |

11 |

  ${title}

12 |

13 |
14 |
15 | 16 |
17 | 18 |
19 | 20 |
21 | 22 | 23 |
24 |

25 |
26 | 27 | 28 |
29 |

30 |
31 | 32 | 33 |
34 |

35 |
36 | 37 | ${config['AuthorName']} 38 | 39 | Filenames must be full path to file
Filename and URL need to end with .jpg/.jpeg/.png
40 |

41 |
42 |
43 |
44 | <% 45 | if config['Manual'] == "1": 46 | checked = 'checked="checked"' 47 | else: 48 | checked = '' 49 | %> 50 | 51 | 52 |
53 |
54 |

55 |
56 |
57 |
58 | 59 | <%def name="javascriptIncludes()"> 60 | 69 | 70 | -------------------------------------------------------------------------------- /data/interfaces/legacy/manualsearch.html: -------------------------------------------------------------------------------- 1 | <%inherit file="base.html"/> 2 | <%! 3 | import lazylibrarian 4 | %> 5 | <%def name="headerIncludes()"> 6 |
7 |
8 |
9 |
10 | 11 | <%def name="body()"> 12 |
13 |
14 |

  ${title}

15 |
16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | %for item in results: 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | %endfor 39 | 40 |
MatchTitleProviderSizeDateStatus
${item['score']} %${item['title']}${item['provider']}${item['size']}${item['date']} Snatch
41 | 42 | <%def name="headIncludes()"> 43 | 44 | 45 | <%def name="javascriptIncludes()"> 46 | 47 | 68 | 69 | -------------------------------------------------------------------------------- /data/interfaces/legacy/response.html: -------------------------------------------------------------------------------- 1 | <%inherit file="base.html"/> 2 | <%def name="headIncludes()"> 3 | 4 | 5 | <%def name="body()"> 6 |
7 |
8 |

${title}

9 |

LazyLibrarian is ${message}

10 |
11 |
12 | 13 | -------------------------------------------------------------------------------- /data/interfaces/legacy/shutdown.html: -------------------------------------------------------------------------------- 1 | <%inherit file="base.html"/> 2 | <%def name="headIncludes()"> 3 | 4 | 5 | <%def name="body()"> 6 |
7 |
8 |

${title}

9 |

LazyLibrarian is ${message}

10 |
11 |
12 | 13 | -------------------------------------------------------------------------------- /data/js/adapt.min.js: -------------------------------------------------------------------------------- 1 | (function(a,b,c,d){function e(){clearTimeout(i);for(var c=a.innerWidth||b.documentElement.clientWidth||b.body.clientWidth||0,e,f,o,p,q=m,u=m-1;q--;){g="",e=l[q].split("="),f=e[0],p=e[1]?e[1].replace(/\s/g,""):d,e=(o=f.match("to"))?parseInt(f.split("to")[0],10):parseInt(f,10),f=o?parseInt(f.split("to")[1],10):d;if(!f&&q===u&&c>e||c>e&&c<=f){p&&(g=k+p);break}}h?h!==g&&(h=n.href=g,j&&j(q,c)):(h=n.href=g,j&&j(q,c),k&&(b.head||b.getElementsByTagName("head")[0]).appendChild(n))}function f(){clearTimeout(i),i=setTimeout(e,16)}if(c){var g,h,i,j=typeof c.callback=="function"?c.callback:d,k=c.path?c.path:"",l=c.range,m=l.length,n=b.createElement("link");n.rel="stylesheet",n.media="screen",e(),c.dynamic&&(a.addEventListener?a.addEventListener("resize",f,!1):a.attachEvent?a.attachEvent("onresize",f):a.onresize=f)}})(this,this.document,ADAPT_CONFIG) -------------------------------------------------------------------------------- /data/js/lazylibrarian-bs.js: -------------------------------------------------------------------------------- 1 | function restartQA(e, message, title) { 2 | var self = this; 3 | 4 | bootbox.confirm("Are you sure you want to restart LazyLibrarian?", function(result) { 5 | if (result) { 6 | self.restart(message, title); 7 | } 8 | }); 9 | 10 | } 11 | 12 | function restart(message, title) { 13 | window.location.href = "restart"; 14 | } 15 | 16 | function shutdownQA(e) { 17 | var self = this; 18 | 19 | bootbox.confirm("Are you sure you want to shutdown LazyLibrarian?", function(result) { 20 | if (result) { 21 | self.shutdown(); 22 | } 23 | }); 24 | } 25 | 26 | function shutdown() { 27 | window.location.href= "shutdown"; 28 | } -------------------------------------------------------------------------------- /data/js/lazylibrarian.js: -------------------------------------------------------------------------------- 1 | function restartQA(e, message, title) { 2 | var self = this; 3 | 4 | var q = new Question('Are you sure you want to restart LazyLibrarian?', 'Restart', [{ 5 | 'text': 'Restart', 6 | 'class': 'restart orange', 7 | 'events': { 8 | 'click': function(e){ 9 | (e).preventDefault(); 10 | self.restart(message, title); 11 | q.close.delay(100, q); 12 | } 13 | } 14 | }, { 15 | 'text': 'Cancel', 16 | 'cancel': true 17 | }]); 18 | } 19 | 20 | function restart(message, title) { 21 | window.location.href = "restart"; 22 | } 23 | 24 | function shutdownQA(e) { 25 | var self = this; 26 | 27 | var q = new Question('Are you sure you want to shutdown LazyLibrarian?', 'Shutdown', [{ 28 | 'text': 'Shutdown', 29 | 'class': 'shutdown red', 30 | 'events': { 31 | 'click': function(e){ 32 | (e).preventDefault(); 33 | self.shutdown(); 34 | q.close.delay(100, q); 35 | } 36 | } 37 | }, { 38 | 'text': 'Cancel', 39 | 'cancel': true 40 | }]); 41 | } 42 | 43 | function shutdown() { 44 | window.location.href= "shutdown"; 45 | } -------------------------------------------------------------------------------- /data/js/libs/natural.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Natural Sort algorithm for Javascript 3 | * Version 0.2 4 | * Author: Jim Palmer (based on chunking idea from Dave Koelle) 5 | * Released under MIT license. 6 | */ 7 | function naturalSort (a, b) { 8 | // setup temp-scope variables for comparison evauluation 9 | var x = a.toString().toLowerCase() || '', y = b.toString().toLowerCase() || '', 10 | nC = String.fromCharCode(0), 11 | xN = x.replace(/([-]{0,1}[0-9.]{1,})/g, nC + '$1' + nC).split(nC), 12 | yN = y.replace(/([-]{0,1}[0-9.]{1,})/g, nC + '$1' + nC).split(nC), 13 | xD = (new Date(x)).getTime(), yD = (new Date(y)).getTime(); 14 | // natural sorting of dates 15 | if ( xD && yD && xD < yD ) 16 | return -1; 17 | else if ( xD && yD && xD > yD ) 18 | return 1; 19 | // natural sorting through split numeric strings and default strings 20 | for ( var cLoc=0, numS = Math.max( xN.length, yN.length ); cLoc < numS; cLoc++ ) 21 | if ( ( parseFloat( xN[cLoc] ) || xN[cLoc] ) < ( parseFloat( yN[cLoc] ) || yN[cLoc] ) ) 22 | return -1; 23 | else if ( ( parseFloat( xN[cLoc] ) || xN[cLoc] ) > ( parseFloat( yN[cLoc] ) || yN[cLoc] ) ) 24 | return 1; 25 | return 0; 26 | } 27 | 28 | jQuery.fn.dataTableExt.oSort['natural-asc'] = function(a,b) { 29 | return naturalSort(a,b); 30 | }; 31 | 32 | jQuery.fn.dataTableExt.oSort['natural-desc'] = function(a,b) { 33 | return naturalSort(a,b) * -1; 34 | }; 35 | -------------------------------------------------------------------------------- /data/js/nav.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | // get document url 3 | var docURL = document.URL; 4 | 5 | // reset class of nav links 6 | $("#navbardiv a").removeClass("navactive"); 7 | 8 | // pull our page 9 | var page = location.pathname.substring( location.pathname.lastIndexOf("/") + 1 ); 10 | 11 | // add active class 12 | $("#navbardiv a:not(.navbarlogo)[href=\""+page+"\"]").addClass("navactive"); 13 | }); 14 | -------------------------------------------------------------------------------- /data/js/plugins.js: -------------------------------------------------------------------------------- 1 | window.log = function(){ 2 | log.history = log.history || []; 3 | log.history.push(arguments); 4 | arguments.callee = arguments.callee.caller; 5 | if(this.console) console.log( Array.prototype.slice.call(arguments) ); 6 | }; 7 | (function(b){function c(){}for(var d="assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","),a;a=d.pop();)b[a]=b[a]||c})(window.console=window.console||{}); 8 | 9 | jQuery.fn.dataTableExt.oSort['title-string-asc'] = function(a,b) { 10 | var x = a.match(/title="(.*?)"/)[1].toLowerCase(); 11 | var y = b.match(/title="(.*?)"/)[1].toLowerCase(); 12 | return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 13 | }; 14 | 15 | jQuery.fn.dataTableExt.oSort['title-string-desc'] = function(a,b) { 16 | var x = a.match(/title="(.*?)"/)[1].toLowerCase(); 17 | var y = b.match(/title="(.*?)"/)[1].toLowerCase(); 18 | return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 19 | }; 20 | 21 | jQuery.fn.dataTableExt.oSort['title-numeric-asc'] = function(a,b) { 22 | var x = a.match(/title="*(-?[0-9]+)/)[1]; 23 | var y = b.match(/title="*(-?[0-9]+)/)[1]; 24 | x = parseFloat( x ); 25 | y = parseFloat( y ); 26 | return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 27 | }; 28 | 29 | jQuery.fn.dataTableExt.oSort['title-numeric-desc'] = function(a,b) { 30 | var x = a.match(/title="*(-?[0-9]+)/)[1]; 31 | var y = b.match(/title="*(-?[0-9]+)/)[1]; 32 | x = parseFloat( x ); 33 | y = parseFloat( y ); 34 | return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 35 | }; 36 | 37 | function toggle(source) { 38 | checkboxes = document.getElementsByClassName('checkbox'); 39 | for(var i in checkboxes) 40 | checkboxes[i].checked = source.checked; 41 | } -------------------------------------------------------------------------------- /data/js/question.js: -------------------------------------------------------------------------------- 1 | var Question = new Class( { 2 | 3 | initialize : function(question, hint, answers) { 4 | var self = this 5 | 6 | self.question = question 7 | self.hint = hint 8 | self.answers = answers 9 | 10 | self.createQuestion() 11 | self.answers.each(function(answer) { 12 | self.createAnswer(answer) 13 | }) 14 | self.createMask() 15 | 16 | }, 17 | 18 | createMask : function() { 19 | var self = this 20 | 21 | self.mask = new Element('div.mask').fade('hide').inject(document.body).fade('in'); 22 | }, 23 | 24 | createQuestion : function() { 25 | 26 | this.container = new Element('div', { 27 | 'class' : 'question' 28 | }).adopt( 29 | new Element('div.title', { 30 | 'html': ('

' + this.hint + '

') 31 | }), 32 | new Element('h3', { 33 | 'html': this.question 34 | }) 35 | ).inject(document.body) 36 | 37 | this.container.position( { 38 | 'position' : 'center' 39 | }); 40 | 41 | }, 42 | 43 | createAnswer : function(options) { 44 | var self = this 45 | 46 | var answer = new Element('a', Object.merge(options, { 47 | 'class': 'answer button ' + (options['class'] || '') + (options['cancel'] ? ' grey cancel' : '') 48 | })).inject(this.container) 49 | 50 | if (options.cancel) { 51 | answer.addEvent('click', self.close.bind(self)) 52 | } 53 | else if (options.request) { 54 | answer.addEvent('click', function(e){ 55 | e.stop(); 56 | new Request(Object.merge(options, { 57 | 'url': options.href, 58 | 'onComplete': function() { 59 | (options.onComplete || function(){})() 60 | self.close(); 61 | } 62 | })).send(); 63 | }); 64 | } 65 | }, 66 | 67 | close : function() { 68 | var self = this; 69 | self.mask.fade('out'); 70 | (function(){self.mask.destroy()}).delay(1000); 71 | 72 | this.container.destroy(); 73 | }, 74 | 75 | toElement : function() { 76 | return this.container 77 | } 78 | 79 | }) 80 | -------------------------------------------------------------------------------- /data/opensearch.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | LazyLibrarian 4 | Search {label} 5 | UTF-8 6 | UTF-8 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /epubandmobi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | # 4 | from __future__ import print_function 5 | 6 | import sys 7 | import os 8 | import subprocess 9 | 10 | converter = "ebook-convert" # if not in your "path", put the full pathname here 11 | calibredb = "calibredb" # and here too 12 | books_parent_dir = '/media/eBooks' # change to your dir 13 | 14 | for root, subFolders, files in os.walk(books_parent_dir): 15 | for name in files: 16 | for source, dest in [['.mobi', '.epub'], ['.epub', '.mobi']]: 17 | if name.endswith(source): 18 | source_file = (os.path.join(root, name)) 19 | dest_file = source_file[:-len(source)] + dest 20 | if not os.path.exists(dest_file): 21 | params = [converter, source_file, dest_file] 22 | if dest == '.mobi': 23 | params.extend(['--output-profile', 'kindle']) 24 | try: 25 | print("Creating %s for %s" % (dest, name)) 26 | res = subprocess.check_output(params, stderr=subprocess.STDOUT) 27 | 28 | try: 29 | calibreid = root.rsplit('(', 1)[1].split(')')[0] 30 | if not calibreid.isdigit(): 31 | calibreid = '' 32 | except IndexError: 33 | calibreid = '' 34 | 35 | if calibreid: 36 | librarydir = os.path.dirname(os.path.dirname(root)) 37 | params = [calibredb, 'add_format', '--with-library=' + librarydir, calibreid, dest_file ] 38 | try: 39 | print("Telling calibre about new %s" % dest) 40 | res = subprocess.check_output(params, stderr=subprocess.STDOUT) 41 | except Exception as e: 42 | print("%s\n" % e) 43 | 44 | except Exception as e: 45 | print("%s\n" % e) 46 | 47 | -------------------------------------------------------------------------------- /example.monthnames.json: -------------------------------------------------------------------------------- 1 | [["en_GB.UTF-8", "en_GB.UTF-8", "es_ES.utf8", "es_ES.utf8"], ["january", "jan", "enero", "ene"], ["february", "feb", "febrero", "feb"], ["march", "mar", "marzo", "mar"], ["april", "apr", "abril", "abr"], ["may", "may", "mayo", "may"], ["june", "jun", "junio", "jun"], ["july", "jul", "julio", "jul"], ["august", "aug", "agosto", "ago"], ["september", "sep", "septiembre", "sep"], ["october", "oct", "octubre", "oct"], ["november", "nov", "noviembre", "nov"], ["december", "dec", "diciembre", "dic"]] -------------------------------------------------------------------------------- /example_custom_notification.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # The parameter list passed is a list of database columns (name and data) 3 | # for a book or magazine. Read them back into a dictionary. 4 | # For this example, just return the formatted dictionary 5 | import sys 6 | 7 | mydict = {} 8 | try: 9 | args = sys.argv[1:] 10 | while len(args) > 1: 11 | mydict[args[0]] = args[1] 12 | args = args[2:] 13 | except Exception as err: 14 | sys.stderr.write("%s\n" % err) 15 | exit(1) 16 | 17 | res = '' 18 | for item in mydict: 19 | # column name: value 20 | res = res + "%s: %s\n" % (item, mydict[item]) 21 | 22 | print(res) 23 | exit(0) 24 | -------------------------------------------------------------------------------- /example_custom_notification.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # The parameter list passed is a list of database columns (name and data) 3 | # for a book or magazine. 4 | # For this example, just write the arguments to a file 5 | 6 | ofile='notification.out' 7 | echo -n "" > $ofile 8 | arg=1 9 | numargs=$# 10 | while (( arg < numargs)); do 11 | # column name 12 | echo -n "${!arg}: " >> $ofile 13 | (( arg += 1 )) 14 | # value 15 | echo "${!arg}" >> $ofile 16 | (( arg += 1 )) 17 | done 18 | -------------------------------------------------------------------------------- /gsconvert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os 4 | import sys 5 | import platform 6 | import subprocess 7 | 8 | if len(sys.argv) != 3: 9 | print "Usage: gsconvert input.pdf output.jpg" 10 | else: 11 | GS = "" 12 | if platform.system() == "Windows": 13 | logger.error("This version of gsconvert does not run under Windows") 14 | else: 15 | GS = os.path.join(os.getcwd(), "gs") 16 | if not os.path.isfile(GS): 17 | params = ["which", "gs"] 18 | try: 19 | GS = subprocess.check_output(params, stderr=subprocess.STDOUT).strip() 20 | except Exception as e: 21 | sys.exit("which gs failed: %s" % str(e)) 22 | if not os.path.isfile(GS): 23 | sys.exit("Cannot find gs, %s" % str(e)) 24 | 25 | try: 26 | params = [GS, "--version"] 27 | res = subprocess.check_output(params, stderr=subprocess.STDOUT) 28 | print("Using gs [%s] version %s" % (GS, res)) 29 | jpeg = sys.argv[2] 30 | pdf = sys.argv[1] 31 | if '[' in pdf: 32 | pdf = pdf.split('[')[0] 33 | params = [GS, "-sDEVICE=jpeg", "-dNOPAUSE", "-dBATCH", "-dSAFER", "-dFirstPage=1", "-dLastPage=1", 34 | "-sOutputFile=%s" % jpeg, pdf] 35 | res = subprocess.check_output(params, stderr=subprocess.STDOUT) 36 | if not os.path.isfile(jpeg): 37 | print("Failed to create jpg: %s" % res) 38 | except subprocess.CalledProcessError as e: 39 | sys.exit("call to subprocess failed: %s" % str(e)) 40 | -------------------------------------------------------------------------------- /init/INSTALL.txt: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Edit lazylibrarian.default if necessary, 4 | # the other files should not need to be changed 5 | # 6 | # Default settings need LazyLibrarian in /opt/lazylibrarian 7 | # and use the users home directory for config, database, logs 8 | # Suitable for ubuntu and other debian based systems, and the 9 | # init.d and default files should work on sysv based systems. 10 | # 11 | # You need to be root to copy the files (or use sudo) 12 | # Copy all three files for systemd (ubuntu,debian etc) 13 | # Copy just the last two files for SysV 14 | cp lazylibrarian.service /lib/systemd/system/lazylibrarian.service 15 | cp lazylibrarian.initd /etc/init.d/lazylibrarian 16 | cp lazylibrarian.default /etc/default/lazylibrarian 17 | # 18 | # To auto-start on a systemd based system 19 | # systemctl enable lazylibrarian 20 | # systemctl start lazylibrarian 21 | # 22 | # To autostart on SysV 23 | # update-rc.d lazylibrarian defaults 24 | -------------------------------------------------------------------------------- /init/lazylibrarian.default: -------------------------------------------------------------------------------- 1 | # This file is sourced by /etc/init.d/lazylibrarian 2 | # 3 | # When lazylibrarian is started using the init script 4 | # is started under the account of $USER, as set below. 5 | # 6 | # Each setting is marked either "required" or "optional"; 7 | # leaving any required setting unconfigured will cause 8 | # the service to not start. 9 | 10 | # [required] set path where lazylibrarian is installed: 11 | APP_PATH=/opt/LazyLibrarian 12 | 13 | # [optional] change to 1 to enable daemon 14 | ENABLE_DAEMON=1 15 | 16 | # [required] user or uid of account to run the program as: 17 | RUN_AS=$USER 18 | 19 | # [optional] change to 1 to enable updating from webinterface 20 | # this changes ownership of /opt/lazylibrarian to user set @ RUN_AS 21 | WEB_UPDATE=1 22 | 23 | # [optional] full path to the configuration file of your choice; 24 | # otherwise, the default location (~/.lazylibrarian) is used: 25 | CONFIG= 26 | 27 | # [optional] full path to the folder to store data (databases/thumbs) in; 28 | # otherwise, the default location (~/.lazylibrarian) is used: 29 | DATADIR= 30 | 31 | # [optional] Force port number to listen on, otherwise the one set in config.ini is used: 32 | PORT= 33 | 34 | # [optional] full path for the pidfile 35 | # otherwise, the default location /var/run/lazylibrarian/lazylibrarian.pid is used: 36 | PID_FILE= 37 | -------------------------------------------------------------------------------- /init/lazylibrarian.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=LazyLibrarian 3 | Comment=LazyLibrarian ebook and magazine manager 4 | Exec=/usr/bin/lazylibrarian 5 | Icon=/opt/lazylibrarian/data/images/ll.png 6 | Terminal=false 7 | Type=Application 8 | Encoding=UTF-8 9 | Categories=Network;Application; 10 | Path= 11 | -------------------------------------------------------------------------------- /init/lazylibrarian.service: -------------------------------------------------------------------------------- 1 | # lazylibrarian.service to run as $USER with config in $HOME/.lazylibrarian 2 | 3 | [Unit] 4 | SourcePath=/etc/init.d/lazylibrarian 5 | Description=LSB: starts instance of LazyLibrarian 6 | After=all.target 7 | 8 | [Service] 9 | Type=forking 10 | Restart=no 11 | TimeoutSec=5min 12 | IgnoreSIGPIPE=no 13 | KillMode=process 14 | GuessMainPID=no 15 | RemainAfterExit=yes 16 | ExecStart=/etc/init.d/lazylibrarian start 17 | ExecStop=/etc/init.d/lazylibrarian stop 18 | 19 | [Install] 20 | WantedBy=multi-user.target 21 | -------------------------------------------------------------------------------- /init/lazylibrarian.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd /opt/lazylibrarian 3 | ./LazyLibrarian.py --datadir=$HOME/.lazylibrarian --config=$HOME/.lazylibrarian/config.ini 4 | -------------------------------------------------------------------------------- /lazylibrarian/classes.py: -------------------------------------------------------------------------------- 1 | # This file is part of LazyLibrarian. 2 | # 3 | # LazyLibrarian is free software: you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation, either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # LazyLibrarian is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with LazyLibrarian. If not, see . 15 | # 16 | # Stolen from Sick-Beard's classes.py ## 17 | # 18 | 19 | 20 | class SearchResult: 21 | 22 | """ 23 | Represents a search result from an indexer. 24 | """ 25 | 26 | def __init__(self): 27 | self.provider = "" 28 | 29 | # URL to the NZB/torrent file 30 | self.url = "" 31 | 32 | # used by some providers to store extra info associated with the result 33 | self.extraInfo = [] 34 | 35 | # release name 36 | self.name = "" 37 | 38 | def __str__(self): 39 | 40 | if self.provider is None: 41 | return "Invalid provider, unable to print self" 42 | 43 | # noinspection PyUnresolvedReferences 44 | myString = self.provider.name + " @ " + self.url + "\n" 45 | myString += "Extra Info:\n" 46 | for extra in self.extraInfo: 47 | myString += " " + extra + "\n" 48 | return myString 49 | 50 | 51 | class NZBSearchResult(SearchResult): 52 | 53 | """ 54 | Regular NZB result with an URL to the NZB 55 | """ 56 | resultType = "nzb" 57 | 58 | 59 | class NZBDataSearchResult(SearchResult): 60 | 61 | """ 62 | NZB result where the actual NZB XML data is stored in the extraInfo 63 | """ 64 | resultType = "nzbdata" 65 | 66 | 67 | class TorrentSearchResult(SearchResult): 68 | 69 | """ 70 | Torrent result with an URL to the torrent 71 | """ 72 | resultType = "torrent" 73 | -------------------------------------------------------------------------------- /lazylibrarian/notifiers/nma.py: -------------------------------------------------------------------------------- 1 | import lazylibrarian 2 | from lazylibrarian import logger 3 | from lazylibrarian.common import notifyStrings, NOTIFY_SNATCH, NOTIFY_DOWNLOAD 4 | from lib.pynma import pynma 5 | 6 | 7 | class NMA_Notifier: 8 | 9 | def __init__(self): 10 | pass 11 | 12 | @staticmethod 13 | def _sendNMA(nma_api=None, nma_priority=None, event=None, message=None, force=False): 14 | 15 | title = "LazyLibrarian" 16 | 17 | # suppress notifications if the notifier is disabled but the notify options are checked 18 | if not lazylibrarian.CONFIG['USE_NMA'] and not force: 19 | return False 20 | 21 | if nma_api is None: 22 | nma_api = lazylibrarian.CONFIG['NMA_APIKEY'] 23 | 24 | if nma_priority is None: 25 | nma_priority = lazylibrarian.CONFIG['NMA_PRIORITY'] 26 | 27 | logger.debug("NMA: title: " + title) 28 | logger.debug("NMA: event: " + event) 29 | logger.debug("NMA: message: " + message) 30 | 31 | batch = False 32 | 33 | p = pynma.PyNMA() 34 | keys = nma_api.split(',') 35 | p.addkey(keys) 36 | 37 | if len(keys) > 1: 38 | batch = True 39 | 40 | response = p.push(title, event, message, priority=nma_priority, batch_mode=batch) 41 | 42 | if not response[nma_api][u'code'] == u'200': 43 | logger.error(u"NMA: Could not send notification to NotifyMyAndroid") 44 | return False 45 | else: 46 | logger.debug(u"NMA: Success. NotifyMyAndroid returned : %s" % response[nma_api][u'code']) 47 | return True 48 | 49 | # 50 | # Public functions 51 | # 52 | 53 | def notify_snatch(self, title): 54 | if lazylibrarian.CONFIG['NMA_ONSNATCH']: 55 | self._sendNMA(nma_priority=None, event=notifyStrings[NOTIFY_SNATCH], message=title) 56 | 57 | def notify_download(self, title): 58 | if lazylibrarian.CONFIG['NMA_ONDOWNLOAD']: 59 | self._sendNMA(nma_priority=None, event=notifyStrings[NOTIFY_DOWNLOAD], message=title) 60 | 61 | # noinspection PyUnusedLocal 62 | def test_notify(self, title="Test"): 63 | return self._sendNMA(nma_priority=None, event="Test", 64 | message="Testing NMA settings from LazyLibrarian", force=True) 65 | 66 | def update_library(self, showName=None): 67 | pass 68 | 69 | 70 | notifier = NMA_Notifier 71 | -------------------------------------------------------------------------------- /lazylibrarian/unittests/test_searchnzb.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from lazylibrarian import searchnzb 4 | 5 | 6 | class SearchNZBTest(unittest.TestCase): 7 | 8 | def test_MakeSearchTermWebSafe(self): 9 | result = searchnzb.MakeSearchTermWebSafe("abc") 10 | self.assertEquals("abc", result) 11 | 12 | def test_MakeSearchTermWebSafe2(self): 13 | result = searchnzb.MakeSearchTermWebSafe("a + b?c") 14 | self.assertEquals("a bc", result) 15 | 16 | 17 | if __name__ == '__main__': 18 | unittest.main() 19 | -------------------------------------------------------------------------------- /lazylibrarian/version.py: -------------------------------------------------------------------------------- 1 | # Change this to "Windows" if building a windows.exe 2 | # or "Package" if you build a .deb .rpm that you don't want to auto update from source 3 | LAZYLIBRARIAN_VERSION = "master" 4 | -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/lib/__init__.py -------------------------------------------------------------------------------- /lib/apscheduler/__init__.py: -------------------------------------------------------------------------------- 1 | version_info = (2, 0, 0, 'rc', 2) 2 | version = '.'.join(str(n) for n in version_info[:3]) 3 | release = version + ''.join(str(n) for n in version_info[3:]) 4 | -------------------------------------------------------------------------------- /lib/apscheduler/jobstores/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/lib/apscheduler/jobstores/__init__.py -------------------------------------------------------------------------------- /lib/apscheduler/jobstores/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | Abstract base class that provides the interface needed by all job stores. 3 | Job store methods are also documented here. 4 | """ 5 | 6 | 7 | class JobStore(object): 8 | def add_job(self, job): 9 | """Adds the given job from this store.""" 10 | raise NotImplementedError 11 | 12 | def update_job(self, job): 13 | """Persists the running state of the given job.""" 14 | raise NotImplementedError 15 | 16 | def remove_job(self, job): 17 | """Removes the given jobs from this store.""" 18 | raise NotImplementedError 19 | 20 | def load_jobs(self): 21 | """Loads jobs from this store into memory.""" 22 | raise NotImplementedError 23 | 24 | def close(self): 25 | """Frees any resources still bound to this job store.""" 26 | -------------------------------------------------------------------------------- /lib/apscheduler/jobstores/ram_store.py: -------------------------------------------------------------------------------- 1 | """ 2 | Stores jobs in an array in RAM. Provides no persistence support. 3 | """ 4 | 5 | from lib.apscheduler.jobstores.base import JobStore 6 | 7 | 8 | class RAMJobStore(JobStore): 9 | def __init__(self): 10 | self.jobs = [] 11 | 12 | def add_job(self, job): 13 | self.jobs.append(job) 14 | 15 | def update_job(self, job): 16 | pass 17 | 18 | def remove_job(self, job): 19 | self.jobs.remove(job) 20 | 21 | def load_jobs(self): 22 | pass 23 | 24 | def __repr__(self): 25 | return '<%s>' % (self.__class__.__name__) 26 | -------------------------------------------------------------------------------- /lib/apscheduler/jobstores/shelve_store.py: -------------------------------------------------------------------------------- 1 | """ 2 | Stores jobs in a file governed by the :mod:`shelve` module. 3 | """ 4 | 5 | import shelve 6 | import pickle 7 | import random 8 | import logging 9 | 10 | from lib.apscheduler.jobstores.base import JobStore 11 | from lib.apscheduler.job import Job 12 | from lib.apscheduler.util import itervalues 13 | 14 | logger = logging.getLogger(__name__) 15 | 16 | 17 | class ShelveJobStore(JobStore): 18 | MAX_ID = 1000000 19 | 20 | def __init__(self, path, pickle_protocol=pickle.HIGHEST_PROTOCOL): 21 | self.jobs = [] 22 | self.path = path 23 | self.pickle_protocol = pickle_protocol 24 | self.store = shelve.open(path, 'c', self.pickle_protocol) 25 | 26 | def _generate_id(self): 27 | id = None 28 | while not id: 29 | id = str(random.randint(1, self.MAX_ID)) 30 | if not id in self.store: 31 | return id 32 | 33 | def add_job(self, job): 34 | job.id = self._generate_id() 35 | self.jobs.append(job) 36 | self.store[job.id] = job.__getstate__() 37 | 38 | def update_job(self, job): 39 | job_dict = self.store[job.id] 40 | job_dict['next_run_time'] = job.next_run_time 41 | job_dict['runs'] = job.runs 42 | self.store[job.id] = job_dict 43 | 44 | def remove_job(self, job): 45 | del self.store[job.id] 46 | self.jobs.remove(job) 47 | 48 | def load_jobs(self): 49 | jobs = [] 50 | for job_dict in itervalues(self.store): 51 | try: 52 | job = Job.__new__(Job) 53 | job.__setstate__(job_dict) 54 | jobs.append(job) 55 | except Exception: 56 | job_name = job_dict.get('name', '(unknown)') 57 | logger.exception('Unable to restore job "%s"', job_name) 58 | 59 | self.jobs = jobs 60 | 61 | def close(self): 62 | self.store.close() 63 | 64 | def __repr__(self): 65 | return '<%s (path=%s)>' % (self.__class__.__name__, self.path) 66 | -------------------------------------------------------------------------------- /lib/apscheduler/triggers/__init__.py: -------------------------------------------------------------------------------- 1 | from lib.apscheduler.triggers.cron import CronTrigger 2 | from lib.apscheduler.triggers.interval import IntervalTrigger 3 | from lib.apscheduler.triggers.simple import SimpleTrigger 4 | -------------------------------------------------------------------------------- /lib/apscheduler/triggers/interval.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta 2 | from math import ceil 3 | 4 | from lib.apscheduler.util import convert_to_datetime, timedelta_seconds 5 | 6 | 7 | class IntervalTrigger(object): 8 | def __init__(self, interval, start_date=None): 9 | if not isinstance(interval, timedelta): 10 | raise TypeError('interval must be a timedelta') 11 | if start_date: 12 | start_date = convert_to_datetime(start_date) 13 | 14 | self.interval = interval 15 | self.interval_length = timedelta_seconds(self.interval) 16 | if self.interval_length == 0: 17 | self.interval = timedelta(seconds=1) 18 | self.interval_length = 1 19 | 20 | if start_date is None: 21 | self.start_date = datetime.now() + self.interval 22 | else: 23 | self.start_date = convert_to_datetime(start_date) 24 | 25 | def get_next_fire_time(self, start_date): 26 | if start_date < self.start_date: 27 | return self.start_date 28 | 29 | timediff_seconds = timedelta_seconds(start_date - self.start_date) 30 | next_interval_num = int(ceil(timediff_seconds / self.interval_length)) 31 | return self.start_date + self.interval * next_interval_num 32 | 33 | def __str__(self): 34 | return 'interval[%s]' % str(self.interval) 35 | 36 | def __repr__(self): 37 | return "<%s (interval=%s, start_date=%s)>" % ( 38 | self.__class__.__name__, repr(self.interval), 39 | repr(self.start_date)) 40 | -------------------------------------------------------------------------------- /lib/apscheduler/triggers/simple.py: -------------------------------------------------------------------------------- 1 | from lib.apscheduler.util import convert_to_datetime 2 | 3 | 4 | class SimpleTrigger(object): 5 | def __init__(self, run_date): 6 | self.run_date = convert_to_datetime(run_date) 7 | 8 | def get_next_fire_time(self, start_date): 9 | if self.run_date >= start_date: 10 | return self.run_date 11 | 12 | def __str__(self): 13 | return 'date[%s]' % str(self.run_date) 14 | 15 | def __repr__(self): 16 | return '<%s (run_date=%s)>' % ( 17 | self.__class__.__name__, repr(self.run_date)) 18 | -------------------------------------------------------------------------------- /lib/bencode/BTL.py: -------------------------------------------------------------------------------- 1 | """bencode.py - `BTL` backwards compatibility support.""" 2 | 3 | # Compatibility with previous versions: 4 | from lib.bencode.exceptions import BencodeDecodeError as BTFailure # noqa: F401 5 | 6 | 7 | __all__ = ( 8 | 'BTFailure' 9 | ) 10 | -------------------------------------------------------------------------------- /lib/bencode/exceptions.py: -------------------------------------------------------------------------------- 1 | """bencode.py - encoder + decode exceptions.""" 2 | 3 | 4 | class BencodeDecodeError(Exception): 5 | """Bencode decode error.""" 6 | 7 | pass 8 | -------------------------------------------------------------------------------- /lib/deluge_client/__init__.py: -------------------------------------------------------------------------------- 1 | from .client import DelugeRPCClient -------------------------------------------------------------------------------- /lib/fuzzywuzzy/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | __version__ = '0.14.0' 3 | -------------------------------------------------------------------------------- /lib/fuzzywuzzy/string_processing.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | import re 3 | import string 4 | import sys 5 | 6 | PY3 = sys.version_info[0] == 3 7 | if PY3: 8 | string = str 9 | 10 | 11 | class StringProcessor(object): 12 | """ 13 | This class defines method to process strings in the most 14 | efficient way. Ideally all the methods below use unicode strings 15 | for both input and output. 16 | """ 17 | 18 | regex = re.compile(r"(?ui)\W") 19 | 20 | @classmethod 21 | def replace_non_letters_non_numbers_with_whitespace(cls, a_string): 22 | """ 23 | This function replaces any sequence of non letters and non 24 | numbers with a single white space. 25 | """ 26 | return cls.regex.sub(" ", a_string) 27 | 28 | strip = staticmethod(string.strip) 29 | to_lower_case = staticmethod(string.lower) 30 | to_upper_case = staticmethod(string.upper) 31 | -------------------------------------------------------------------------------- /lib/fuzzywuzzy/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | import sys 3 | import functools 4 | 5 | from lib.fuzzywuzzy.string_processing import StringProcessor 6 | 7 | 8 | PY3 = sys.version_info[0] == 3 9 | 10 | 11 | def validate_string(s): 12 | try: 13 | return len(s) > 0 14 | except TypeError: 15 | return False 16 | 17 | 18 | def check_for_none(func): 19 | @functools.wraps(func) 20 | def decorator(*args, **kwargs): 21 | if args[0] is None or args[1] is None: 22 | return 0 23 | return func(*args, **kwargs) 24 | return decorator 25 | 26 | 27 | def check_empty_string(func): 28 | @functools.wraps(func) 29 | def decorator(*args, **kwargs): 30 | if len(args[0]) == 0 or len(args[1]) == 0: 31 | return 0 32 | return func(*args, **kwargs) 33 | return decorator 34 | 35 | 36 | bad_chars = str("").join([chr(i) for i in range(128, 256)]) # ascii dammit! 37 | if PY3: 38 | translation_table = dict((ord(c), None) for c in bad_chars) 39 | unicode = str 40 | 41 | 42 | def asciionly(s): 43 | if PY3: 44 | return s.translate(translation_table) 45 | else: 46 | return s.translate(None, bad_chars) 47 | 48 | 49 | def asciidammit(s): 50 | if type(s) is str: 51 | return asciionly(s) 52 | elif type(s) is unicode: 53 | return asciionly(s.encode('ascii', 'ignore')) 54 | else: 55 | return asciidammit(unicode(s)) 56 | 57 | 58 | def make_type_consistent(s1, s2): 59 | """If both objects aren't either both string or unicode instances force them to unicode""" 60 | if isinstance(s1, str) and isinstance(s2, str): 61 | return s1, s2 62 | 63 | elif isinstance(s1, unicode) and isinstance(s2, unicode): 64 | return s1, s2 65 | 66 | else: 67 | return unicode(s1), unicode(s2) 68 | 69 | 70 | def full_process(s, force_ascii=False): 71 | """Process string by 72 | -- removing all but letters and numbers 73 | -- trim whitespace 74 | -- force to lower case 75 | if force_ascii == True, force convert to ascii""" 76 | 77 | if s is None: 78 | return "" 79 | 80 | if force_ascii: 81 | s = asciidammit(s) 82 | # Keep only Letters and Numbers (see Unicode docs). 83 | string_out = StringProcessor.replace_non_letters_non_numbers_with_whitespace(s) 84 | # Force into lowercase. 85 | string_out = StringProcessor.to_lower_case(string_out) 86 | # Remove leading and trailing whitespaces. 87 | string_out = StringProcessor.strip(string_out) 88 | return string_out 89 | 90 | 91 | def intr(n): 92 | '''Returns a correctly rounded integer''' 93 | return int(round(n)) 94 | -------------------------------------------------------------------------------- /lib/gntp/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Paul Traylor 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /lib/gntp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/lib/gntp/__init__.py -------------------------------------------------------------------------------- /lib/gntp/config.py: -------------------------------------------------------------------------------- 1 | # Copyright: 2013 Paul Traylor 2 | # These sources are released under the terms of the MIT license: see LICENSE 3 | 4 | """ 5 | The gntp.config module is provided as an extended GrowlNotifier object that takes 6 | advantage of the ConfigParser module to allow us to setup some default values 7 | (such as hostname, password, and port) in a more global way to be shared among 8 | programs using gntp 9 | """ 10 | import logging 11 | import os 12 | 13 | from . import notifier 14 | from . import shim 15 | 16 | __all__ = [ 17 | 'mini', 18 | 'GrowlNotifier' 19 | ] 20 | 21 | logger = logging.getLogger(__name__) 22 | 23 | 24 | class GrowlNotifier(notifier.GrowlNotifier): 25 | """ 26 | ConfigParser enhanced GrowlNotifier object 27 | 28 | For right now, we are only interested in letting users overide certain 29 | values from ~/.gntp 30 | 31 | :: 32 | 33 | [gntp] 34 | hostname = ? 35 | password = ? 36 | port = ? 37 | """ 38 | def __init__(self, *args, **kwargs): 39 | config = shim.RawConfigParser({ 40 | 'hostname': kwargs.get('hostname', 'localhost'), 41 | 'password': kwargs.get('password'), 42 | 'port': kwargs.get('port', 23053), 43 | }) 44 | 45 | config.read([os.path.expanduser('~/.gntp')]) 46 | 47 | # If the file does not exist, then there will be no gntp section defined 48 | # and the config.get() lines below will get confused. Since we are not 49 | # saving the config, it should be safe to just add it here so the 50 | # code below doesn't complain 51 | if not config.has_section('gntp'): 52 | logger.info('Error reading ~/.gntp config file') 53 | config.add_section('gntp') 54 | 55 | kwargs['password'] = config.get('gntp', 'password') 56 | kwargs['hostname'] = config.get('gntp', 'hostname') 57 | kwargs['port'] = config.getint('gntp', 'port') 58 | 59 | super(GrowlNotifier, self).__init__(*args, **kwargs) 60 | 61 | 62 | def mini(description, **kwargs): 63 | """Single notification function 64 | 65 | Simple notification function in one line. Has only one required parameter 66 | and attempts to use reasonable defaults for everything else 67 | :param string description: Notification message 68 | """ 69 | kwargs['notifierFactory'] = GrowlNotifier 70 | notifier.mini(description, **kwargs) 71 | 72 | 73 | if __name__ == '__main__': 74 | # If we're running this module directly we're likely running it as a test 75 | # so extra debugging is useful 76 | logging.basicConfig(level=logging.INFO) 77 | mini('Testing mini notification') 78 | -------------------------------------------------------------------------------- /lib/gntp/errors.py: -------------------------------------------------------------------------------- 1 | # Copyright: 2013 Paul Traylor 2 | # These sources are released under the terms of the MIT license: see LICENSE 3 | 4 | class BaseError(Exception): 5 | pass 6 | 7 | 8 | class ParseError(BaseError): 9 | errorcode = 500 10 | errordesc = 'Error parsing the message' 11 | 12 | 13 | class AuthError(BaseError): 14 | errorcode = 400 15 | errordesc = 'Error with authorization' 16 | 17 | 18 | class UnsupportedError(BaseError): 19 | errorcode = 500 20 | errordesc = 'Currently unsupported by gntp.py' 21 | 22 | 23 | class NetworkError(BaseError): 24 | errorcode = 500 25 | errordesc = "Error connecting to growl server" 26 | -------------------------------------------------------------------------------- /lib/gntp/shim.py: -------------------------------------------------------------------------------- 1 | # Copyright: 2013 Paul Traylor 2 | # These sources are released under the terms of the MIT license: see LICENSE 3 | 4 | """ 5 | Python2.5 and Python3.3 compatibility shim 6 | 7 | Heavily inspirted by the "six" library. 8 | https://pypi.python.org/pypi/six 9 | """ 10 | 11 | import sys 12 | 13 | PY3 = sys.version_info[0] == 3 14 | 15 | if PY3: 16 | def b(s): 17 | if isinstance(s, bytes): 18 | return s 19 | return s.encode('utf8', 'replace') 20 | 21 | def u(s): 22 | if isinstance(s, bytes): 23 | return s.decode('utf8', 'replace') 24 | return s 25 | 26 | from io import BytesIO as StringIO 27 | from configparser import RawConfigParser 28 | else: 29 | def b(s): 30 | if isinstance(s, unicode): 31 | return s.encode('utf8', 'replace') 32 | return s 33 | 34 | def u(s): 35 | if isinstance(s, unicode): 36 | return s 37 | if isinstance(s, int): 38 | s = str(s) 39 | return unicode(s, "utf8", "replace") 40 | 41 | from StringIO import StringIO 42 | from ConfigParser import RawConfigParser 43 | 44 | b.__doc__ = "Ensure we have a byte string" 45 | u.__doc__ = "Ensure we have a unicode string" 46 | -------------------------------------------------------------------------------- /lib/gntp/version.py: -------------------------------------------------------------------------------- 1 | # Copyright: 2013 Paul Traylor 2 | # These sources are released under the terms of the MIT license: see LICENSE 3 | 4 | __version__ = '1.0.2' 5 | -------------------------------------------------------------------------------- /lib/html5lib/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | HTML parsing library based on the WHATWG "HTML5" 3 | specification. The parser is designed to be compatible with existing 4 | HTML found in the wild and implements well-defined error recovery that 5 | is largely compatible with modern desktop web browsers. 6 | 7 | Example usage: 8 | 9 | import html5lib 10 | f = open("my_document.html") 11 | tree = html5lib.parse(f) 12 | """ 13 | 14 | from __future__ import absolute_import, division, unicode_literals 15 | 16 | from .html5parser import HTMLParser, parse, parseFragment 17 | from .treebuilders import getTreeBuilder 18 | from .treewalkers import getTreeWalker 19 | from .serializer import serialize 20 | 21 | __all__ = ["HTMLParser", "parse", "parseFragment", "getTreeBuilder", 22 | "getTreeWalker", "serialize"] 23 | 24 | # this has to be at the top level, see how setup.py parses this 25 | __version__ = "1.0b10" 26 | -------------------------------------------------------------------------------- /lib/html5lib/_trie/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | 3 | from .py import Trie as PyTrie 4 | 5 | Trie = PyTrie 6 | 7 | # pylint:disable=wrong-import-position 8 | try: 9 | from .datrie import Trie as DATrie 10 | except ImportError: 11 | pass 12 | else: 13 | Trie = DATrie 14 | # pylint:enable=wrong-import-position 15 | -------------------------------------------------------------------------------- /lib/html5lib/_trie/_base.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | 3 | from collections import Mapping 4 | 5 | 6 | class Trie(Mapping): 7 | """Abstract base class for tries""" 8 | 9 | def keys(self, prefix=None): 10 | # pylint:disable=arguments-differ 11 | keys = super(Trie, self).keys() 12 | 13 | if prefix is None: 14 | return set(keys) 15 | 16 | # Python 2.6: no set comprehensions 17 | return set([x for x in keys if x.startswith(prefix)]) 18 | 19 | def has_keys_with_prefix(self, prefix): 20 | for key in self.keys(): 21 | if key.startswith(prefix): 22 | return True 23 | 24 | return False 25 | 26 | def longest_prefix(self, prefix): 27 | if prefix in self: 28 | return prefix 29 | 30 | for i in range(1, len(prefix) + 1): 31 | if prefix[:-i] in self: 32 | return prefix[:-i] 33 | 34 | raise KeyError(prefix) 35 | 36 | def longest_prefix_item(self, prefix): 37 | lprefix = self.longest_prefix(prefix) 38 | return (lprefix, self[lprefix]) 39 | -------------------------------------------------------------------------------- /lib/html5lib/_trie/datrie.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | 3 | from datrie import Trie as DATrie 4 | from lib.six import text_type 5 | 6 | from ._base import Trie as ABCTrie 7 | 8 | 9 | class Trie(ABCTrie): 10 | def __init__(self, data): 11 | chars = set() 12 | for key in data.keys(): 13 | if not isinstance(key, text_type): 14 | raise TypeError("All keys must be strings") 15 | for char in key: 16 | chars.add(char) 17 | 18 | self._data = DATrie("".join(chars)) 19 | for key, value in data.items(): 20 | self._data[key] = value 21 | 22 | def __contains__(self, key): 23 | return key in self._data 24 | 25 | def __len__(self): 26 | return len(self._data) 27 | 28 | def __iter__(self): 29 | raise NotImplementedError() 30 | 31 | def __getitem__(self, key): 32 | return self._data[key] 33 | 34 | def keys(self, prefix=None): 35 | return self._data.keys(prefix) 36 | 37 | def has_keys_with_prefix(self, prefix): 38 | return self._data.has_keys_with_prefix(prefix) 39 | 40 | def longest_prefix(self, prefix): 41 | return self._data.longest_prefix(prefix) 42 | 43 | def longest_prefix_item(self, prefix): 44 | return self._data.longest_prefix_item(prefix) 45 | -------------------------------------------------------------------------------- /lib/html5lib/_trie/py.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | from lib.six import text_type 3 | 4 | from bisect import bisect_left 5 | 6 | from ._base import Trie as ABCTrie 7 | 8 | 9 | class Trie(ABCTrie): 10 | def __init__(self, data): 11 | if not all(isinstance(x, text_type) for x in data.keys()): 12 | raise TypeError("All keys must be strings") 13 | 14 | self._data = data 15 | self._keys = sorted(data.keys()) 16 | self._cachestr = "" 17 | self._cachepoints = (0, len(data)) 18 | 19 | def __contains__(self, key): 20 | return key in self._data 21 | 22 | def __len__(self): 23 | return len(self._data) 24 | 25 | def __iter__(self): 26 | return iter(self._data) 27 | 28 | def __getitem__(self, key): 29 | return self._data[key] 30 | 31 | def keys(self, prefix=None): 32 | if prefix is None or prefix == "" or not self._keys: 33 | return set(self._keys) 34 | 35 | if prefix.startswith(self._cachestr): 36 | lo, hi = self._cachepoints 37 | start = i = bisect_left(self._keys, prefix, lo, hi) 38 | else: 39 | start = i = bisect_left(self._keys, prefix) 40 | 41 | keys = set() 42 | if start == len(self._keys): 43 | return keys 44 | 45 | while self._keys[i].startswith(prefix): 46 | keys.add(self._keys[i]) 47 | i += 1 48 | 49 | self._cachestr = prefix 50 | self._cachepoints = (start, i) 51 | 52 | return keys 53 | 54 | def has_keys_with_prefix(self, prefix): 55 | if prefix in self._data: 56 | return True 57 | 58 | if prefix.startswith(self._cachestr): 59 | lo, hi = self._cachepoints 60 | i = bisect_left(self._keys, prefix, lo, hi) 61 | else: 62 | i = bisect_left(self._keys, prefix) 63 | 64 | if i == len(self._keys): 65 | return False 66 | 67 | return self._keys[i].startswith(prefix) 68 | -------------------------------------------------------------------------------- /lib/html5lib/filters/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/lib/html5lib/filters/__init__.py -------------------------------------------------------------------------------- /lib/html5lib/filters/alphabeticalattributes.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | 3 | from . import base 4 | 5 | try: 6 | from collections import OrderedDict 7 | except ImportError: 8 | from ordereddict import OrderedDict 9 | 10 | 11 | class Filter(base.Filter): 12 | def __iter__(self): 13 | for token in base.Filter.__iter__(self): 14 | if token["type"] in ("StartTag", "EmptyTag"): 15 | attrs = OrderedDict() 16 | for name, value in sorted(token["data"].items(), 17 | key=lambda x: x[0]): 18 | attrs[name] = value 19 | token["data"] = attrs 20 | yield token 21 | -------------------------------------------------------------------------------- /lib/html5lib/filters/base.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | 3 | 4 | class Filter(object): 5 | def __init__(self, source): 6 | self.source = source 7 | 8 | def __iter__(self): 9 | return iter(self.source) 10 | 11 | def __getattr__(self, name): 12 | return getattr(self.source, name) 13 | -------------------------------------------------------------------------------- /lib/html5lib/filters/whitespace.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | 3 | import re 4 | 5 | from . import base 6 | from ..constants import rcdataElements, spaceCharacters 7 | spaceCharacters = "".join(spaceCharacters) 8 | 9 | SPACES_REGEX = re.compile("[%s]+" % spaceCharacters) 10 | 11 | 12 | class Filter(base.Filter): 13 | 14 | spacePreserveElements = frozenset(["pre", "textarea"] + list(rcdataElements)) 15 | 16 | def __iter__(self): 17 | preserve = 0 18 | for token in base.Filter.__iter__(self): 19 | type = token["type"] 20 | if type == "StartTag" \ 21 | and (preserve or token["name"] in self.spacePreserveElements): 22 | preserve += 1 23 | 24 | elif type == "EndTag" and preserve: 25 | preserve -= 1 26 | 27 | elif not preserve and type == "SpaceCharacters" and token["data"]: 28 | # Test on token["data"] above to not introduce spaces where there were not 29 | token["data"] = " " 30 | 31 | elif not preserve and type == "Characters": 32 | token["data"] = collapse_spaces(token["data"]) 33 | 34 | yield token 35 | 36 | 37 | def collapse_spaces(text): 38 | return SPACES_REGEX.sub(' ', text) 39 | -------------------------------------------------------------------------------- /lib/html5lib/treeadapters/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | 3 | from . import sax 4 | 5 | __all__ = ["sax"] 6 | 7 | try: 8 | from . import genshi # noqa 9 | except ImportError: 10 | pass 11 | else: 12 | __all__.append("genshi") 13 | -------------------------------------------------------------------------------- /lib/html5lib/treeadapters/genshi.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | 3 | from genshi.core import QName, Attrs 4 | from genshi.core import START, END, TEXT, COMMENT, DOCTYPE 5 | 6 | 7 | def to_genshi(walker): 8 | text = [] 9 | for token in walker: 10 | type = token["type"] 11 | if type in ("Characters", "SpaceCharacters"): 12 | text.append(token["data"]) 13 | elif text: 14 | yield TEXT, "".join(text), (None, -1, -1) 15 | text = [] 16 | 17 | if type in ("StartTag", "EmptyTag"): 18 | if token["namespace"]: 19 | name = "{%s}%s" % (token["namespace"], token["name"]) 20 | else: 21 | name = token["name"] 22 | attrs = Attrs([(QName("{%s}%s" % attr if attr[0] is not None else attr[1]), value) 23 | for attr, value in token["data"].items()]) 24 | yield (START, (QName(name), attrs), (None, -1, -1)) 25 | if type == "EmptyTag": 26 | type = "EndTag" 27 | 28 | if type == "EndTag": 29 | if token["namespace"]: 30 | name = "{%s}%s" % (token["namespace"], token["name"]) 31 | else: 32 | name = token["name"] 33 | 34 | yield END, QName(name), (None, -1, -1) 35 | 36 | elif type == "Comment": 37 | yield COMMENT, token["data"], (None, -1, -1) 38 | 39 | elif type == "Doctype": 40 | yield DOCTYPE, (token["name"], token["publicId"], 41 | token["systemId"]), (None, -1, -1) 42 | 43 | else: 44 | pass # FIXME: What to do? 45 | 46 | if text: 47 | yield TEXT, "".join(text), (None, -1, -1) 48 | -------------------------------------------------------------------------------- /lib/html5lib/treeadapters/sax.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | 3 | from xml.sax.xmlreader import AttributesNSImpl 4 | 5 | from ..constants import adjustForeignAttributes, unadjustForeignAttributes 6 | 7 | prefix_mapping = {} 8 | for prefix, localName, namespace in adjustForeignAttributes.values(): 9 | if prefix is not None: 10 | prefix_mapping[prefix] = namespace 11 | 12 | 13 | def to_sax(walker, handler): 14 | """Call SAX-like content handler based on treewalker walker""" 15 | handler.startDocument() 16 | for prefix, namespace in prefix_mapping.items(): 17 | handler.startPrefixMapping(prefix, namespace) 18 | 19 | for token in walker: 20 | type = token["type"] 21 | if type == "Doctype": 22 | continue 23 | elif type in ("StartTag", "EmptyTag"): 24 | attrs = AttributesNSImpl(token["data"], 25 | unadjustForeignAttributes) 26 | handler.startElementNS((token["namespace"], token["name"]), 27 | token["name"], 28 | attrs) 29 | if type == "EmptyTag": 30 | handler.endElementNS((token["namespace"], token["name"]), 31 | token["name"]) 32 | elif type == "EndTag": 33 | handler.endElementNS((token["namespace"], token["name"]), 34 | token["name"]) 35 | elif type in ("Characters", "SpaceCharacters"): 36 | handler.characters(token["data"]) 37 | elif type == "Comment": 38 | pass 39 | else: 40 | assert False, "Unknown token type" 41 | 42 | for prefix, namespace in prefix_mapping.items(): 43 | handler.endPrefixMapping(prefix) 44 | handler.endDocument() 45 | -------------------------------------------------------------------------------- /lib/html5lib/treewalkers/dom.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | 3 | from xml.dom import Node 4 | 5 | from . import base 6 | 7 | 8 | class TreeWalker(base.NonRecursiveTreeWalker): 9 | def getNodeDetails(self, node): 10 | if node.nodeType == Node.DOCUMENT_TYPE_NODE: 11 | return base.DOCTYPE, node.name, node.publicId, node.systemId 12 | 13 | elif node.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): 14 | return base.TEXT, node.nodeValue 15 | 16 | elif node.nodeType == Node.ELEMENT_NODE: 17 | attrs = {} 18 | for attr in list(node.attributes.keys()): 19 | attr = node.getAttributeNode(attr) 20 | if attr.namespaceURI: 21 | attrs[(attr.namespaceURI, attr.localName)] = attr.value 22 | else: 23 | attrs[(None, attr.name)] = attr.value 24 | return (base.ELEMENT, node.namespaceURI, node.nodeName, 25 | attrs, node.hasChildNodes()) 26 | 27 | elif node.nodeType == Node.COMMENT_NODE: 28 | return base.COMMENT, node.nodeValue 29 | 30 | elif node.nodeType in (Node.DOCUMENT_NODE, Node.DOCUMENT_FRAGMENT_NODE): 31 | return (base.DOCUMENT,) 32 | 33 | else: 34 | return base.UNKNOWN, node.nodeType 35 | 36 | def getFirstChild(self, node): 37 | return node.firstChild 38 | 39 | def getNextSibling(self, node): 40 | return node.nextSibling 41 | 42 | def getParentNode(self, node): 43 | return node.parentNode 44 | -------------------------------------------------------------------------------- /lib/html5lib/treewalkers/genshi.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division, unicode_literals 2 | 3 | from genshi.core import QName 4 | from genshi.core import START, END, XML_NAMESPACE, DOCTYPE, TEXT 5 | from genshi.core import START_NS, END_NS, START_CDATA, END_CDATA, PI, COMMENT 6 | 7 | from . import base 8 | 9 | from ..constants import voidElements, namespaces 10 | 11 | 12 | class TreeWalker(base.TreeWalker): 13 | def __iter__(self): 14 | # Buffer the events so we can pass in the following one 15 | previous = None 16 | for event in self.tree: 17 | if previous is not None: 18 | for token in self.tokens(previous, event): 19 | yield token 20 | previous = event 21 | 22 | # Don't forget the final event! 23 | if previous is not None: 24 | for token in self.tokens(previous, None): 25 | yield token 26 | 27 | def tokens(self, event, next): 28 | kind, data, _ = event 29 | if kind == START: 30 | tag, attribs = data 31 | name = tag.localname 32 | namespace = tag.namespace 33 | converted_attribs = {} 34 | for k, v in attribs: 35 | if isinstance(k, QName): 36 | converted_attribs[(k.namespace, k.localname)] = v 37 | else: 38 | converted_attribs[(None, k)] = v 39 | 40 | if namespace == namespaces["html"] and name in voidElements: 41 | for token in self.emptyTag(namespace, name, converted_attribs, 42 | not next or next[0] != END or 43 | next[1] != tag): 44 | yield token 45 | else: 46 | yield self.startTag(namespace, name, converted_attribs) 47 | 48 | elif kind == END: 49 | name = data.localname 50 | namespace = data.namespace 51 | if namespace != namespaces["html"] or name not in voidElements: 52 | yield self.endTag(namespace, name) 53 | 54 | elif kind == COMMENT: 55 | yield self.comment(data) 56 | 57 | elif kind == TEXT: 58 | for token in self.text(data): 59 | yield token 60 | 61 | elif kind == DOCTYPE: 62 | yield self.doctype(*data) 63 | 64 | elif kind in (XML_NAMESPACE, DOCTYPE, START_NS, END_NS, 65 | START_CDATA, END_CDATA, PI): 66 | pass 67 | 68 | else: 69 | yield self.unknown(kind) 70 | -------------------------------------------------------------------------------- /lib/mobi/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | utils.py 5 | 6 | Created by Elliot Kroo on 2009-12-25. 7 | Copyright (c) 2009 Elliot Kroo. All rights reserved. 8 | """ 9 | 10 | import sys 11 | import os 12 | import unittest 13 | 14 | 15 | def toDict(tuples): 16 | resultsDict = {} 17 | for field, value in tuples: 18 | if len(field) > 0 and field[0] != "-": 19 | resultsDict[field] = value 20 | return resultsDict; 21 | -------------------------------------------------------------------------------- /lib/oauth2/lazylibrarian.note: -------------------------------------------------------------------------------- 1 | This version of oauth2 included with lazylibrarian 2 | is not up-to-date as later versions (also called 1.0) 3 | have issues with goodreads private profiles when reading 4 | users bookshelves (403 errors). This is the last known working 5 | version. Have not looked into why. 6 | -------------------------------------------------------------------------------- /lib/pynma/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from .pynma import PyNMA 4 | 5 | -------------------------------------------------------------------------------- /lib/requests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # __ 4 | # /__) _ _ _ _ _/ _ 5 | # / ( (- (/ (/ (- _) / _) 6 | # / 7 | 8 | """ 9 | Requests HTTP library 10 | ~~~~~~~~~~~~~~~~~~~~~ 11 | 12 | Requests is an HTTP library, written in Python, for human beings. Basic GET 13 | usage: 14 | 15 | >>> import requests 16 | >>> r = requests.get('https://www.python.org') 17 | >>> r.status_code 18 | 200 19 | >>> 'Python is a programming language' in r.content 20 | True 21 | 22 | ... or POST: 23 | 24 | >>> payload = dict(key1='value1', key2='value2') 25 | >>> r = requests.post('http://httpbin.org/post', data=payload) 26 | >>> print(r.text) 27 | { 28 | ... 29 | "form": { 30 | "key2": "value2", 31 | "key1": "value1" 32 | }, 33 | ... 34 | } 35 | 36 | The other HTTP methods are supported - see `requests.api`. Full documentation 37 | is at . 38 | 39 | :copyright: (c) 2016 by Kenneth Reitz. 40 | :license: Apache 2.0, see LICENSE for more details. 41 | """ 42 | 43 | __title__ = 'requests' 44 | __version__ = '2.12.4' 45 | __build__ = 0x021204 46 | __author__ = 'Kenneth Reitz' 47 | __license__ = 'Apache 2.0' 48 | __copyright__ = 'Copyright 2016 Kenneth Reitz' 49 | 50 | # Attempt to enable urllib3's SNI support, if possible 51 | try: 52 | from .packages.urllib3.contrib import pyopenssl 53 | pyopenssl.inject_into_urllib3() 54 | except (ImportError, AttributeError): 55 | pass 56 | 57 | import warnings 58 | 59 | # urllib3's DependencyWarnings should be silenced. 60 | from .packages.urllib3.exceptions import DependencyWarning 61 | warnings.simplefilter('ignore', DependencyWarning) 62 | 63 | from . import utils 64 | from .models import Request, Response, PreparedRequest 65 | from .api import request, get, head, post, patch, put, delete, options 66 | from .sessions import session, Session 67 | from .status_codes import codes 68 | from .exceptions import ( 69 | RequestException, Timeout, URLRequired, 70 | TooManyRedirects, HTTPError, ConnectionError, 71 | FileModeWarning, ConnectTimeout, ReadTimeout 72 | ) 73 | 74 | # Set default logging handler to avoid "No handler found" warnings. 75 | import logging 76 | try: # Python 2.7+ 77 | from logging import NullHandler 78 | except ImportError: 79 | class NullHandler(logging.Handler): 80 | def emit(self, record): 81 | pass 82 | 83 | logging.getLogger(__name__).addHandler(NullHandler()) 84 | 85 | # FileModeWarnings go off per the default. 86 | warnings.simplefilter('default', FileModeWarning, append=True) 87 | -------------------------------------------------------------------------------- /lib/requests/_internal_utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | requests._internal_utils 5 | ~~~~~~~~~~~~~~ 6 | 7 | Provides utility functions that are consumed internally by Requests 8 | which depend on extremely few external helpers (such as compat) 9 | """ 10 | 11 | from .compat import is_py2, builtin_str, str 12 | 13 | 14 | def to_native_string(string, encoding='ascii'): 15 | """Given a string object, regardless of type, returns a representation of 16 | that string in the native string type, encoding and decoding where 17 | necessary. This assumes ASCII unless told otherwise. 18 | """ 19 | if isinstance(string, builtin_str): 20 | out = string 21 | else: 22 | if is_py2: 23 | out = string.encode(encoding) 24 | else: 25 | out = string.decode(encoding) 26 | 27 | return out 28 | 29 | 30 | def unicode_is_ascii(u_string): 31 | """Determine if unicode string only contains ASCII characters. 32 | 33 | :param str u_string: unicode string to check. Must be unicode 34 | and not Python 2 `str`. 35 | :rtype: bool 36 | """ 37 | assert isinstance(u_string, str) 38 | try: 39 | u_string.encode('ascii') 40 | return True 41 | except UnicodeEncodeError: 42 | return False 43 | -------------------------------------------------------------------------------- /lib/requests/certs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | requests.certs 6 | ~~~~~~~~~~~~~~ 7 | 8 | This module returns the preferred default CA certificate bundle. 9 | 10 | If you are packaging Requests, e.g., for a Linux distribution or a managed 11 | environment, you can change the definition of where() to return a separately 12 | packaged CA bundle. 13 | """ 14 | import os.path 15 | 16 | try: 17 | from certifi import where 18 | except ImportError: 19 | def where(): 20 | """Return the preferred certificate bundle.""" 21 | # vendored bundle inside Requests 22 | return os.path.join(os.path.dirname(__file__), 'cacert.pem') 23 | 24 | if __name__ == '__main__': 25 | print(where()) 26 | -------------------------------------------------------------------------------- /lib/requests/compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | requests.compat 5 | ~~~~~~~~~~~~~~~ 6 | 7 | This module handles import compatibility issues between Python 2 and 8 | Python 3. 9 | """ 10 | 11 | from .packages import chardet 12 | 13 | import sys 14 | 15 | # ------- 16 | # Pythons 17 | # ------- 18 | 19 | # Syntax sugar. 20 | _ver = sys.version_info 21 | 22 | #: Python 2.x? 23 | is_py2 = (_ver[0] == 2) 24 | 25 | #: Python 3.x? 26 | is_py3 = (_ver[0] == 3) 27 | 28 | try: 29 | import lib.simplejson as json 30 | except (ImportError, SyntaxError): 31 | # simplejson does not support Python 3.2, it throws a SyntaxError 32 | # because of u'...' Unicode literals. 33 | import json 34 | 35 | # --------- 36 | # Specifics 37 | # --------- 38 | 39 | if is_py2: 40 | from urllib import quote, unquote, quote_plus, unquote_plus, urlencode, getproxies, proxy_bypass 41 | from urlparse import urlparse, urlunparse, urljoin, urlsplit, urldefrag 42 | from urllib2 import parse_http_list 43 | import cookielib 44 | from Cookie import Morsel 45 | from StringIO import StringIO 46 | from .packages.urllib3.packages.ordered_dict import OrderedDict 47 | 48 | builtin_str = str 49 | bytes = str 50 | str = unicode 51 | basestring = basestring 52 | numeric_types = (int, long, float) 53 | integer_types = (int, long) 54 | 55 | elif is_py3: 56 | from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote, quote_plus, unquote_plus, urldefrag 57 | from urllib.request import parse_http_list, getproxies, proxy_bypass 58 | from http import cookiejar as cookielib 59 | from http.cookies import Morsel 60 | from io import StringIO 61 | from collections import OrderedDict 62 | 63 | builtin_str = str 64 | str = str 65 | bytes = bytes 66 | basestring = (str, bytes) 67 | numeric_types = (int, float) 68 | integer_types = (int,) 69 | -------------------------------------------------------------------------------- /lib/requests/hooks.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | requests.hooks 5 | ~~~~~~~~~~~~~~ 6 | 7 | This module provides the capabilities for the Requests hooks system. 8 | 9 | Available hooks: 10 | 11 | ``response``: 12 | The response generated from a Request. 13 | """ 14 | HOOKS = ['response'] 15 | 16 | 17 | def default_hooks(): 18 | return dict((event, []) for event in HOOKS) 19 | 20 | # TODO: response is the only one 21 | 22 | 23 | def dispatch_hook(key, hooks, hook_data, **kwargs): 24 | """Dispatches a hook dictionary on a given piece of data.""" 25 | hooks = hooks or dict() 26 | hooks = hooks.get(key) 27 | if hooks: 28 | if hasattr(hooks, '__call__'): 29 | hooks = [hooks] 30 | for hook in hooks: 31 | _hook_data = hook(hook_data, **kwargs) 32 | if _hook_data is not None: 33 | hook_data = _hook_data 34 | return hook_data 35 | -------------------------------------------------------------------------------- /lib/requests/packages/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Debian and other distributions "unbundle" requests' vendored dependencies, and 3 | rewrite all imports to use the global versions of ``urllib3`` and ``chardet``. 4 | The problem with this is that not only requests itself imports those 5 | dependencies, but third-party code outside of the distros' control too. 6 | 7 | In reaction to these problems, the distro maintainers replaced 8 | ``requests.packages`` with a magical "stub module" that imports the correct 9 | modules. The implementations were varying in quality and all had severe 10 | problems. For example, a symlink (or hardlink) that links the correct modules 11 | into place introduces problems regarding object identity, since you now have 12 | two modules in `sys.modules` with the same API, but different identities:: 13 | 14 | requests.packages.urllib3 is not urllib3 15 | 16 | With version ``2.5.2``, requests started to maintain its own stub, so that 17 | distro-specific breakage would be reduced to a minimum, even though the whole 18 | issue is not requests' fault in the first place. See 19 | https://github.com/kennethreitz/requests/pull/2375 for the corresponding pull 20 | request. 21 | ''' 22 | 23 | from __future__ import absolute_import 24 | import sys 25 | 26 | try: 27 | from . import urllib3 28 | except ImportError: 29 | import urllib3 30 | sys.modules['%s.urllib3' % __name__] = urllib3 31 | 32 | try: 33 | from . import chardet 34 | except ImportError: 35 | import chardet 36 | sys.modules['%s.chardet' % __name__] = chardet 37 | 38 | try: 39 | from . import idna 40 | except ImportError: 41 | import idna 42 | sys.modules['%s.idna' % __name__] = idna 43 | -------------------------------------------------------------------------------- /lib/requests/packages/chardet/__init__.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # This library is free software; you can redistribute it and/or 3 | # modify it under the terms of the GNU Lesser General Public 4 | # License as published by the Free Software Foundation; either 5 | # version 2.1 of the License, or (at your option) any later version. 6 | # 7 | # This library is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | # Lesser General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU Lesser General Public 13 | # License along with this library; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 15 | # 02110-1301 USA 16 | ######################### END LICENSE BLOCK ######################### 17 | 18 | __version__ = "2.3.0" 19 | from sys import version_info 20 | 21 | 22 | def detect(aBuf): 23 | if ((version_info < (3, 0) and isinstance(aBuf, unicode)) or 24 | (version_info >= (3, 0) and not isinstance(aBuf, bytes))): 25 | raise ValueError('Expected a bytes object, not a unicode object') 26 | 27 | from . import universaldetector 28 | u = universaldetector.UniversalDetector() 29 | u.reset() 30 | u.feed(aBuf) 31 | u.close() 32 | return u.result 33 | -------------------------------------------------------------------------------- /lib/requests/packages/chardet/big5prober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is Mozilla Communicator client code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .mbcharsetprober import MultiByteCharSetProber 29 | from .codingstatemachine import CodingStateMachine 30 | from .chardistribution import Big5DistributionAnalysis 31 | from .mbcssm import Big5SMModel 32 | 33 | 34 | class Big5Prober(MultiByteCharSetProber): 35 | def __init__(self): 36 | MultiByteCharSetProber.__init__(self) 37 | self._mCodingSM = CodingStateMachine(Big5SMModel) 38 | self._mDistributionAnalyzer = Big5DistributionAnalysis() 39 | self.reset() 40 | 41 | def get_charset_name(self): 42 | return "Big5" 43 | -------------------------------------------------------------------------------- /lib/requests/packages/chardet/charsetprober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is Mozilla Universal charset detector code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 2001 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # Shy Shalom - original C code 12 | # 13 | # This library is free software; you can redistribute it and/or 14 | # modify it under the terms of the GNU Lesser General Public 15 | # License as published by the Free Software Foundation; either 16 | # version 2.1 of the License, or (at your option) any later version. 17 | # 18 | # This library is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU Lesser General Public 24 | # License along with this library; if not, write to the Free Software 25 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 26 | # 02110-1301 USA 27 | ######################### END LICENSE BLOCK ######################### 28 | 29 | from . import constants 30 | import re 31 | 32 | 33 | class CharSetProber: 34 | def __init__(self): 35 | pass 36 | 37 | def reset(self): 38 | self._mState = constants.eDetecting 39 | 40 | def get_charset_name(self): 41 | return None 42 | 43 | def feed(self, aBuf): 44 | pass 45 | 46 | def get_state(self): 47 | return self._mState 48 | 49 | def get_confidence(self): 50 | return 0.0 51 | 52 | def filter_high_bit_only(self, aBuf): 53 | aBuf = re.sub(b'([\x00-\x7F])+', b' ', aBuf) 54 | return aBuf 55 | 56 | def filter_without_english_letters(self, aBuf): 57 | aBuf = re.sub(b'([A-Za-z])+', b' ', aBuf) 58 | return aBuf 59 | 60 | def filter_with_english_letters(self, aBuf): 61 | # TODO 62 | return aBuf 63 | -------------------------------------------------------------------------------- /lib/requests/packages/chardet/codingstatemachine.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .constants import eStart 29 | from .compat import wrap_ord 30 | 31 | 32 | class CodingStateMachine: 33 | def __init__(self, sm): 34 | self._mModel = sm 35 | self._mCurrentBytePos = 0 36 | self._mCurrentCharLen = 0 37 | self.reset() 38 | 39 | def reset(self): 40 | self._mCurrentState = eStart 41 | 42 | def next_state(self, c): 43 | # for each byte we get its class 44 | # if it is first byte, we also get byte length 45 | # PY3K: aBuf is a byte stream, so c is an int, not a byte 46 | byteCls = self._mModel['classTable'][wrap_ord(c)] 47 | if self._mCurrentState == eStart: 48 | self._mCurrentBytePos = 0 49 | self._mCurrentCharLen = self._mModel['charLenTable'][byteCls] 50 | # from byte's class and stateTable, we get its next state 51 | curr_state = (self._mCurrentState * self._mModel['classFactor'] 52 | + byteCls) 53 | self._mCurrentState = self._mModel['stateTable'][curr_state] 54 | self._mCurrentBytePos += 1 55 | return self._mCurrentState 56 | 57 | def get_current_charlen(self): 58 | return self._mCurrentCharLen 59 | 60 | def get_coding_state_machine(self): 61 | return self._mModel['name'] 62 | -------------------------------------------------------------------------------- /lib/requests/packages/chardet/compat.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # Contributor(s): 3 | # Ian Cordasco - port to Python 4 | # 5 | # This library is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU Lesser General Public 7 | # License as published by the Free Software Foundation; either 8 | # version 2.1 of the License, or (at your option) any later version. 9 | # 10 | # This library is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # Lesser General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public 16 | # License along with this library; if not, write to the Free Software 17 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 | # 02110-1301 USA 19 | ######################### END LICENSE BLOCK ######################### 20 | 21 | import sys 22 | 23 | 24 | if sys.version_info < (3, 0): 25 | base_str = (str, unicode) 26 | else: 27 | base_str = (bytes, str) 28 | 29 | 30 | def wrap_ord(a): 31 | if sys.version_info < (3, 0) and isinstance(a, base_str): 32 | return ord(a) 33 | else: 34 | return a 35 | -------------------------------------------------------------------------------- /lib/requests/packages/chardet/constants.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is Mozilla Universal charset detector code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 2001 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # Shy Shalom - original C code 12 | # 13 | # This library is free software; you can redistribute it and/or 14 | # modify it under the terms of the GNU Lesser General Public 15 | # License as published by the Free Software Foundation; either 16 | # version 2.1 of the License, or (at your option) any later version. 17 | # 18 | # This library is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | # Lesser General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU Lesser General Public 24 | # License along with this library; if not, write to the Free Software 25 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 26 | # 02110-1301 USA 27 | ######################### END LICENSE BLOCK ######################### 28 | 29 | _debug = 0 30 | 31 | eDetecting = 0 32 | eFoundIt = 1 33 | eNotMe = 2 34 | 35 | eStart = 0 36 | eError = 1 37 | eItsMe = 2 38 | 39 | SHORTCUT_THRESHOLD = 0.95 40 | -------------------------------------------------------------------------------- /lib/requests/packages/chardet/cp949prober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .mbcharsetprober import MultiByteCharSetProber 29 | from .codingstatemachine import CodingStateMachine 30 | from .chardistribution import EUCKRDistributionAnalysis 31 | from .mbcssm import CP949SMModel 32 | 33 | 34 | class CP949Prober(MultiByteCharSetProber): 35 | def __init__(self): 36 | MultiByteCharSetProber.__init__(self) 37 | self._mCodingSM = CodingStateMachine(CP949SMModel) 38 | # NOTE: CP949 is a superset of EUC-KR, so the distribution should be 39 | # not different. 40 | self._mDistributionAnalyzer = EUCKRDistributionAnalysis() 41 | self.reset() 42 | 43 | def get_charset_name(self): 44 | return "CP949" 45 | -------------------------------------------------------------------------------- /lib/requests/packages/chardet/euckrprober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .mbcharsetprober import MultiByteCharSetProber 29 | from .codingstatemachine import CodingStateMachine 30 | from .chardistribution import EUCKRDistributionAnalysis 31 | from .mbcssm import EUCKRSMModel 32 | 33 | 34 | class EUCKRProber(MultiByteCharSetProber): 35 | def __init__(self): 36 | MultiByteCharSetProber.__init__(self) 37 | self._mCodingSM = CodingStateMachine(EUCKRSMModel) 38 | self._mDistributionAnalyzer = EUCKRDistributionAnalysis() 39 | self.reset() 40 | 41 | def get_charset_name(self): 42 | return "EUC-KR" 43 | -------------------------------------------------------------------------------- /lib/requests/packages/chardet/euctwprober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .mbcharsetprober import MultiByteCharSetProber 29 | from .codingstatemachine import CodingStateMachine 30 | from .chardistribution import EUCTWDistributionAnalysis 31 | from .mbcssm import EUCTWSMModel 32 | 33 | class EUCTWProber(MultiByteCharSetProber): 34 | def __init__(self): 35 | MultiByteCharSetProber.__init__(self) 36 | self._mCodingSM = CodingStateMachine(EUCTWSMModel) 37 | self._mDistributionAnalyzer = EUCTWDistributionAnalysis() 38 | self.reset() 39 | 40 | def get_charset_name(self): 41 | return "EUC-TW" 42 | -------------------------------------------------------------------------------- /lib/requests/packages/chardet/gb2312prober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is mozilla.org code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 1998 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # 12 | # This library is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU Lesser General Public 14 | # License as published by the Free Software Foundation; either 15 | # version 2.1 of the License, or (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | # Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public 23 | # License along with this library; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 25 | # 02110-1301 USA 26 | ######################### END LICENSE BLOCK ######################### 27 | 28 | from .mbcharsetprober import MultiByteCharSetProber 29 | from .codingstatemachine import CodingStateMachine 30 | from .chardistribution import GB2312DistributionAnalysis 31 | from .mbcssm import GB2312SMModel 32 | 33 | class GB2312Prober(MultiByteCharSetProber): 34 | def __init__(self): 35 | MultiByteCharSetProber.__init__(self) 36 | self._mCodingSM = CodingStateMachine(GB2312SMModel) 37 | self._mDistributionAnalyzer = GB2312DistributionAnalysis() 38 | self.reset() 39 | 40 | def get_charset_name(self): 41 | return "GB2312" 42 | -------------------------------------------------------------------------------- /lib/requests/packages/chardet/mbcsgroupprober.py: -------------------------------------------------------------------------------- 1 | ######################## BEGIN LICENSE BLOCK ######################## 2 | # The Original Code is Mozilla Universal charset detector code. 3 | # 4 | # The Initial Developer of the Original Code is 5 | # Netscape Communications Corporation. 6 | # Portions created by the Initial Developer are Copyright (C) 2001 7 | # the Initial Developer. All Rights Reserved. 8 | # 9 | # Contributor(s): 10 | # Mark Pilgrim - port to Python 11 | # Shy Shalom - original C code 12 | # Proofpoint, Inc. 13 | # 14 | # This library is free software; you can redistribute it and/or 15 | # modify it under the terms of the GNU Lesser General Public 16 | # License as published by the Free Software Foundation; either 17 | # version 2.1 of the License, or (at your option) any later version. 18 | # 19 | # This library is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 | # Lesser General Public License for more details. 23 | # 24 | # You should have received a copy of the GNU Lesser General Public 25 | # License along with this library; if not, write to the Free Software 26 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 27 | # 02110-1301 USA 28 | ######################### END LICENSE BLOCK ######################### 29 | 30 | from .charsetgroupprober import CharSetGroupProber 31 | from .utf8prober import UTF8Prober 32 | from .sjisprober import SJISProber 33 | from .eucjpprober import EUCJPProber 34 | from .gb2312prober import GB2312Prober 35 | from .euckrprober import EUCKRProber 36 | from .cp949prober import CP949Prober 37 | from .big5prober import Big5Prober 38 | from .euctwprober import EUCTWProber 39 | 40 | 41 | class MBCSGroupProber(CharSetGroupProber): 42 | def __init__(self): 43 | CharSetGroupProber.__init__(self) 44 | self._mProbers = [ 45 | UTF8Prober(), 46 | SJISProber(), 47 | EUCJPProber(), 48 | GB2312Prober(), 49 | EUCKRProber(), 50 | CP949Prober(), 51 | Big5Prober(), 52 | EUCTWProber() 53 | ] 54 | self.reset() 55 | -------------------------------------------------------------------------------- /lib/requests/packages/idna/__init__.py: -------------------------------------------------------------------------------- 1 | from .core import * 2 | -------------------------------------------------------------------------------- /lib/requests/packages/idna/compat.py: -------------------------------------------------------------------------------- 1 | from .core import * 2 | from .codec import * 3 | 4 | def ToASCII(label): 5 | return encode(label) 6 | 7 | def ToUnicode(label): 8 | return decode(label) 9 | 10 | def nameprep(s): 11 | raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") 12 | 13 | -------------------------------------------------------------------------------- /lib/requests/packages/idna/intranges.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a list of integers, made up of (hopefully) a small number of long runs 3 | of consecutive integers, compute a representation of the form 4 | ((start1, end1), (start2, end2) ...). Then answer the question "was x present 5 | in the original list?" in time O(log(# runs)). 6 | """ 7 | 8 | import bisect 9 | 10 | def intranges_from_list(list_): 11 | """Represent a list of integers as a sequence of ranges: 12 | ((start_0, end_0), (start_1, end_1), ...), such that the original 13 | integers are exactly those x such that start_i <= x < end_i for some i. 14 | """ 15 | 16 | sorted_list = sorted(list_) 17 | ranges = [] 18 | last_write = -1 19 | for i in range(len(sorted_list)): 20 | if i+1 < len(sorted_list): 21 | if sorted_list[i] == sorted_list[i+1]-1: 22 | continue 23 | current_range = sorted_list[last_write+1:i+1] 24 | range_tuple = (current_range[0], current_range[-1] + 1) 25 | ranges.append(range_tuple) 26 | last_write = i 27 | 28 | return tuple(ranges) 29 | 30 | 31 | def intranges_contain(int_, ranges): 32 | """Determine if `int_` falls into one of the ranges in `ranges`.""" 33 | tuple_ = (int_, int_) 34 | pos = bisect.bisect_left(ranges, tuple_) 35 | # we could be immediately ahead of a tuple (start, end) 36 | # with start < int_ <= end 37 | if pos > 0: 38 | left, right = ranges[pos-1] 39 | if left <= int_ < right: 40 | return True 41 | # or we could be immediately behind a tuple (int_, end) 42 | if pos < len(ranges): 43 | left, _ = ranges[pos] 44 | if left == int_: 45 | return True 46 | return False 47 | -------------------------------------------------------------------------------- /lib/requests/packages/urllib3/contrib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/lib/requests/packages/urllib3/contrib/__init__.py -------------------------------------------------------------------------------- /lib/requests/packages/urllib3/packages/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from . import ssl_match_hostname 4 | 5 | __all__ = ('ssl_match_hostname', ) 6 | -------------------------------------------------------------------------------- /lib/requests/packages/urllib3/packages/backports/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/lib/requests/packages/urllib3/packages/backports/__init__.py -------------------------------------------------------------------------------- /lib/requests/packages/urllib3/packages/backports/makefile.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | backports.makefile 4 | ~~~~~~~~~~~~~~~~~~ 5 | 6 | Backports the Python 3 ``socket.makefile`` method for use with anything that 7 | wants to create a "fake" socket object. 8 | """ 9 | import io 10 | 11 | from socket import SocketIO 12 | 13 | 14 | def backport_makefile(self, mode="r", buffering=None, encoding=None, 15 | errors=None, newline=None): 16 | """ 17 | Backport of ``socket.makefile`` from Python 3.5. 18 | """ 19 | if not set(mode) <= set(["r", "w", "b"]): 20 | raise ValueError( 21 | "invalid mode %r (only r, w, b allowed)" % (mode,) 22 | ) 23 | writing = "w" in mode 24 | reading = "r" in mode or not writing 25 | assert reading or writing 26 | binary = "b" in mode 27 | rawmode = "" 28 | if reading: 29 | rawmode += "r" 30 | if writing: 31 | rawmode += "w" 32 | raw = SocketIO(self, rawmode) 33 | self._makefile_refs += 1 34 | if buffering is None: 35 | buffering = -1 36 | if buffering < 0: 37 | buffering = io.DEFAULT_BUFFER_SIZE 38 | if buffering == 0: 39 | if not binary: 40 | raise ValueError("unbuffered streams must be binary") 41 | return raw 42 | if reading and writing: 43 | buffer = io.BufferedRWPair(raw, raw, buffering) 44 | elif reading: 45 | buffer = io.BufferedReader(raw, buffering) 46 | else: 47 | assert writing 48 | buffer = io.BufferedWriter(raw, buffering) 49 | if binary: 50 | return buffer 51 | text = io.TextIOWrapper(buffer, encoding, errors, newline) 52 | text.mode = mode 53 | return text 54 | -------------------------------------------------------------------------------- /lib/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | try: 4 | # Our match_hostname function is the same as 3.5's, so we only want to 5 | # import the match_hostname function if it's at least that good. 6 | if sys.version_info < (3, 5): 7 | raise ImportError("Fallback to vendored code") 8 | 9 | from ssl import CertificateError, match_hostname 10 | except ImportError: 11 | try: 12 | # Backport of the function from a pypi module 13 | from backports.ssl_match_hostname import CertificateError, match_hostname 14 | except ImportError: 15 | # Our vendored copy 16 | from ._implementation import CertificateError, match_hostname 17 | 18 | # Not needed, but documenting what we provide. 19 | __all__ = ('CertificateError', 'match_hostname') 20 | -------------------------------------------------------------------------------- /lib/requests/packages/urllib3/util/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | # For backwards compatibility, provide imports that used to be here. 3 | from .connection import is_connection_dropped 4 | from .request import make_headers 5 | from .response import is_fp_closed 6 | from .ssl_ import ( 7 | SSLContext, 8 | HAS_SNI, 9 | IS_PYOPENSSL, 10 | assert_fingerprint, 11 | resolve_cert_reqs, 12 | resolve_ssl_version, 13 | ssl_wrap_socket, 14 | ) 15 | from .timeout import ( 16 | current_time, 17 | Timeout, 18 | ) 19 | 20 | from .retry import Retry 21 | from .url import ( 22 | get_host, 23 | parse_url, 24 | split_first, 25 | Url, 26 | ) 27 | 28 | __all__ = ( 29 | 'HAS_SNI', 30 | 'IS_PYOPENSSL', 31 | 'SSLContext', 32 | 'Retry', 33 | 'Timeout', 34 | 'Url', 35 | 'assert_fingerprint', 36 | 'current_time', 37 | 'is_connection_dropped', 38 | 'is_fp_closed', 39 | 'get_host', 40 | 'parse_url', 41 | 'make_headers', 42 | 'resolve_cert_reqs', 43 | 'resolve_ssl_version', 44 | 'split_first', 45 | 'ssl_wrap_socket', 46 | ) 47 | -------------------------------------------------------------------------------- /lib/requests/packages/urllib3/util/request.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from base64 import b64encode 3 | 4 | from ..packages.six import b 5 | 6 | ACCEPT_ENCODING = 'gzip,deflate' 7 | 8 | 9 | def make_headers(keep_alive=None, accept_encoding=None, user_agent=None, 10 | basic_auth=None, proxy_basic_auth=None, disable_cache=None): 11 | """ 12 | Shortcuts for generating request headers. 13 | 14 | :param keep_alive: 15 | If ``True``, adds 'connection: keep-alive' header. 16 | 17 | :param accept_encoding: 18 | Can be a boolean, list, or string. 19 | ``True`` translates to 'gzip,deflate'. 20 | List will get joined by comma. 21 | String will be used as provided. 22 | 23 | :param user_agent: 24 | String representing the user-agent you want, such as 25 | "python-urllib3/0.6" 26 | 27 | :param basic_auth: 28 | Colon-separated username:password string for 'authorization: basic ...' 29 | auth header. 30 | 31 | :param proxy_basic_auth: 32 | Colon-separated username:password string for 'proxy-authorization: basic ...' 33 | auth header. 34 | 35 | :param disable_cache: 36 | If ``True``, adds 'cache-control: no-cache' header. 37 | 38 | Example:: 39 | 40 | >>> make_headers(keep_alive=True, user_agent="Batman/1.0") 41 | {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'} 42 | >>> make_headers(accept_encoding=True) 43 | {'accept-encoding': 'gzip,deflate'} 44 | """ 45 | headers = {} 46 | if accept_encoding: 47 | if isinstance(accept_encoding, str): 48 | pass 49 | elif isinstance(accept_encoding, list): 50 | accept_encoding = ','.join(accept_encoding) 51 | else: 52 | accept_encoding = ACCEPT_ENCODING 53 | headers['accept-encoding'] = accept_encoding 54 | 55 | if user_agent: 56 | headers['user-agent'] = user_agent 57 | 58 | if keep_alive: 59 | headers['connection'] = 'keep-alive' 60 | 61 | if basic_auth: 62 | headers['authorization'] = 'Basic ' + \ 63 | b64encode(b(basic_auth)).decode('utf-8') 64 | 65 | if proxy_basic_auth: 66 | headers['proxy-authorization'] = 'Basic ' + \ 67 | b64encode(b(proxy_basic_auth)).decode('utf-8') 68 | 69 | if disable_cache: 70 | headers['cache-control'] = 'no-cache' 71 | 72 | return headers 73 | -------------------------------------------------------------------------------- /lib/requests/packages/urllib3/util/response.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from ..packages.six.moves import http_client as httplib 3 | 4 | from ..exceptions import HeaderParsingError 5 | 6 | 7 | def is_fp_closed(obj): 8 | """ 9 | Checks whether a given file-like object is closed. 10 | 11 | :param obj: 12 | The file-like object to check. 13 | """ 14 | 15 | try: 16 | # Check `isclosed()` first, in case Python3 doesn't set `closed`. 17 | # GH Issue #928 18 | return obj.isclosed() 19 | except AttributeError: 20 | pass 21 | 22 | try: 23 | # Check via the official file-like-object way. 24 | return obj.closed 25 | except AttributeError: 26 | pass 27 | 28 | try: 29 | # Check if the object is a container for another file-like object that 30 | # gets released on exhaustion (e.g. HTTPResponse). 31 | return obj.fp is None 32 | except AttributeError: 33 | pass 34 | 35 | raise ValueError("Unable to determine whether fp is closed.") 36 | 37 | 38 | def assert_header_parsing(headers): 39 | """ 40 | Asserts whether all headers have been successfully parsed. 41 | Extracts encountered errors from the result of parsing headers. 42 | 43 | Only works on Python 3. 44 | 45 | :param headers: Headers to verify. 46 | :type headers: `httplib.HTTPMessage`. 47 | 48 | :raises urllib3.exceptions.HeaderParsingError: 49 | If parsing errors are found. 50 | """ 51 | 52 | # This will fail silently if we pass in the wrong kind of parameter. 53 | # To make debugging easier add an explicit check. 54 | if not isinstance(headers, httplib.HTTPMessage): 55 | raise TypeError('expected httplib.Message, got {0}.'.format( 56 | type(headers))) 57 | 58 | defects = getattr(headers, 'defects', None) 59 | get_payload = getattr(headers, 'get_payload', None) 60 | 61 | unparsed_data = None 62 | if get_payload: # Platform-specific: Python 3. 63 | unparsed_data = get_payload() 64 | 65 | if defects or unparsed_data: 66 | raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data) 67 | 68 | 69 | def is_response_to_head(response): 70 | """ 71 | Checks whether the request of a response has been a HEAD-request. 72 | Handles the quirks of AppEngine. 73 | 74 | :param conn: 75 | :type conn: :class:`httplib.HTTPResponse` 76 | """ 77 | # FIXME: Can we do this somehow without accessing private httplib _method? 78 | method = response._method 79 | if isinstance(method, int): # Platform-specific: Appengine 80 | return method == 3 81 | return method.upper() == 'HEAD' 82 | -------------------------------------------------------------------------------- /lib/simplejson/compat.py: -------------------------------------------------------------------------------- 1 | """Python 3 compatibility shims 2 | """ 3 | import sys 4 | if sys.version_info[0] < 3: 5 | PY3 = False 6 | def b(s): 7 | return s 8 | def u(s): 9 | return unicode(s, 'unicode_escape') 10 | import cStringIO as StringIO 11 | StringIO = BytesIO = StringIO.StringIO 12 | text_type = unicode 13 | binary_type = str 14 | string_types = (basestring,) 15 | integer_types = (int, long) 16 | unichr = unichr 17 | reload_module = reload 18 | else: 19 | PY3 = True 20 | if sys.version_info[:2] >= (3, 4): 21 | from importlib import reload as reload_module 22 | else: 23 | from imp import reload as reload_module 24 | import codecs 25 | def b(s): 26 | return codecs.latin_1_encode(s)[0] 27 | def u(s): 28 | return s 29 | import io 30 | StringIO = io.StringIO 31 | BytesIO = io.BytesIO 32 | text_type = str 33 | binary_type = bytes 34 | string_types = (str,) 35 | integer_types = (int,) 36 | 37 | def unichr(s): 38 | return u(chr(s)) 39 | 40 | long_type = integer_types[-1] 41 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_bigint_as_string.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import simplejson as json 4 | 5 | 6 | class TestBigintAsString(TestCase): 7 | # Python 2.5, at least the one that ships on Mac OS X, calculates 8 | # 2 ** 53 as 0! It manages to calculate 1 << 53 correctly. 9 | values = [(200, 200), 10 | ((1 << 53) - 1, 9007199254740991), 11 | ((1 << 53), '9007199254740992'), 12 | ((1 << 53) + 1, '9007199254740993'), 13 | (-100, -100), 14 | ((-1 << 53), '-9007199254740992'), 15 | ((-1 << 53) - 1, '-9007199254740993'), 16 | ((-1 << 53) + 1, -9007199254740991)] 17 | 18 | options = ( 19 | {"bigint_as_string": True}, 20 | {"int_as_string_bitcount": 53} 21 | ) 22 | 23 | def test_ints(self): 24 | for opts in self.options: 25 | for val, expect in self.values: 26 | self.assertEqual( 27 | val, 28 | json.loads(json.dumps(val))) 29 | self.assertEqual( 30 | expect, 31 | json.loads(json.dumps(val, **opts))) 32 | 33 | def test_lists(self): 34 | for opts in self.options: 35 | for val, expect in self.values: 36 | val = [val, val] 37 | expect = [expect, expect] 38 | self.assertEqual( 39 | val, 40 | json.loads(json.dumps(val))) 41 | self.assertEqual( 42 | expect, 43 | json.loads(json.dumps(val, **opts))) 44 | 45 | def test_dicts(self): 46 | for opts in self.options: 47 | for val, expect in self.values: 48 | val = {'k': val} 49 | expect = {'k': expect} 50 | self.assertEqual( 51 | val, 52 | json.loads(json.dumps(val))) 53 | self.assertEqual( 54 | expect, 55 | json.loads(json.dumps(val, **opts))) 56 | 57 | def test_dict_keys(self): 58 | for opts in self.options: 59 | for val, _ in self.values: 60 | expect = {str(val): 'value'} 61 | val = {val: 'value'} 62 | self.assertEqual( 63 | expect, 64 | json.loads(json.dumps(val))) 65 | self.assertEqual( 66 | expect, 67 | json.loads(json.dumps(val, **opts))) 68 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_bitsize_int_as_string.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import simplejson as json 4 | 5 | 6 | class TestBitSizeIntAsString(TestCase): 7 | # Python 2.5, at least the one that ships on Mac OS X, calculates 8 | # 2 ** 31 as 0! It manages to calculate 1 << 31 correctly. 9 | values = [ 10 | (200, 200), 11 | ((1 << 31) - 1, (1 << 31) - 1), 12 | ((1 << 31), str(1 << 31)), 13 | ((1 << 31) + 1, str((1 << 31) + 1)), 14 | (-100, -100), 15 | ((-1 << 31), str(-1 << 31)), 16 | ((-1 << 31) - 1, str((-1 << 31) - 1)), 17 | ((-1 << 31) + 1, (-1 << 31) + 1), 18 | ] 19 | 20 | def test_invalid_counts(self): 21 | for n in ['foo', -1, 0, 1.0]: 22 | self.assertRaises( 23 | TypeError, 24 | json.dumps, 0, int_as_string_bitcount=n) 25 | 26 | def test_ints_outside_range_fails(self): 27 | self.assertNotEqual( 28 | str(1 << 15), 29 | json.loads(json.dumps(1 << 15, int_as_string_bitcount=16)), 30 | ) 31 | 32 | def test_ints(self): 33 | for val, expect in self.values: 34 | self.assertEqual( 35 | val, 36 | json.loads(json.dumps(val))) 37 | self.assertEqual( 38 | expect, 39 | json.loads(json.dumps(val, int_as_string_bitcount=31)), 40 | ) 41 | 42 | def test_lists(self): 43 | for val, expect in self.values: 44 | val = [val, val] 45 | expect = [expect, expect] 46 | self.assertEqual( 47 | val, 48 | json.loads(json.dumps(val))) 49 | self.assertEqual( 50 | expect, 51 | json.loads(json.dumps(val, int_as_string_bitcount=31))) 52 | 53 | def test_dicts(self): 54 | for val, expect in self.values: 55 | val = {'k': val} 56 | expect = {'k': expect} 57 | self.assertEqual( 58 | val, 59 | json.loads(json.dumps(val))) 60 | self.assertEqual( 61 | expect, 62 | json.loads(json.dumps(val, int_as_string_bitcount=31))) 63 | 64 | def test_dict_keys(self): 65 | for val, _ in self.values: 66 | expect = {str(val): 'value'} 67 | val = {val: 'value'} 68 | self.assertEqual( 69 | expect, 70 | json.loads(json.dumps(val))) 71 | self.assertEqual( 72 | expect, 73 | json.loads(json.dumps(val, int_as_string_bitcount=31))) 74 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_check_circular.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | import simplejson as json 3 | 4 | def default_iterable(obj): 5 | return list(obj) 6 | 7 | class TestCheckCircular(TestCase): 8 | def test_circular_dict(self): 9 | dct = {} 10 | dct['a'] = dct 11 | self.assertRaises(ValueError, json.dumps, dct) 12 | 13 | def test_circular_list(self): 14 | lst = [] 15 | lst.append(lst) 16 | self.assertRaises(ValueError, json.dumps, lst) 17 | 18 | def test_circular_composite(self): 19 | dct2 = {} 20 | dct2['a'] = [] 21 | dct2['a'].append(dct2) 22 | self.assertRaises(ValueError, json.dumps, dct2) 23 | 24 | def test_circular_default(self): 25 | json.dumps([set()], default=default_iterable) 26 | self.assertRaises(TypeError, json.dumps, [set()]) 27 | 28 | def test_circular_off_default(self): 29 | json.dumps([set()], default=default_iterable, check_circular=False) 30 | self.assertRaises(TypeError, json.dumps, [set()], check_circular=False) 31 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_default.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import simplejson as json 4 | 5 | class TestDefault(TestCase): 6 | def test_default(self): 7 | self.assertEqual( 8 | json.dumps(type, default=repr), 9 | json.dumps(repr(type))) 10 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_encode_basestring_ascii.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import simplejson.encoder 4 | from simplejson.compat import b 5 | 6 | CASES = [ 7 | (u'/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'), 8 | (u'\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'), 9 | (u'controls', '"controls"'), 10 | (u'\x08\x0c\n\r\t', '"\\b\\f\\n\\r\\t"'), 11 | (u'{"object with 1 member":["array with 1 element"]}', '"{\\"object with 1 member\\":[\\"array with 1 element\\"]}"'), 12 | (u' s p a c e d ', '" s p a c e d "'), 13 | (u'\U0001d120', '"\\ud834\\udd20"'), 14 | (u'\u03b1\u03a9', '"\\u03b1\\u03a9"'), 15 | (b('\xce\xb1\xce\xa9'), '"\\u03b1\\u03a9"'), 16 | (u'\u03b1\u03a9', '"\\u03b1\\u03a9"'), 17 | (b('\xce\xb1\xce\xa9'), '"\\u03b1\\u03a9"'), 18 | (u'\u03b1\u03a9', '"\\u03b1\\u03a9"'), 19 | (u'\u03b1\u03a9', '"\\u03b1\\u03a9"'), 20 | (u"`1~!@#$%^&*()_+-={':[,]}|;.?", '"`1~!@#$%^&*()_+-={\':[,]}|;.?"'), 21 | (u'\x08\x0c\n\r\t', '"\\b\\f\\n\\r\\t"'), 22 | (u'\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'), 23 | ] 24 | 25 | class TestEncodeBaseStringAscii(TestCase): 26 | def test_py_encode_basestring_ascii(self): 27 | self._test_encode_basestring_ascii(simplejson.encoder.py_encode_basestring_ascii) 28 | 29 | def test_c_encode_basestring_ascii(self): 30 | if not simplejson.encoder.c_encode_basestring_ascii: 31 | return 32 | self._test_encode_basestring_ascii(simplejson.encoder.c_encode_basestring_ascii) 33 | 34 | def _test_encode_basestring_ascii(self, encode_basestring_ascii): 35 | fname = encode_basestring_ascii.__name__ 36 | for input_string, expect in CASES: 37 | result = encode_basestring_ascii(input_string) 38 | #self.assertEqual(result, expect, 39 | # '{0!r} != {1!r} for {2}({3!r})'.format( 40 | # result, expect, fname, input_string)) 41 | self.assertEqual(result, expect, 42 | '%r != %r for %s(%r)' % (result, expect, fname, input_string)) 43 | 44 | def test_sorted_dict(self): 45 | items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)] 46 | s = simplejson.dumps(dict(items), sort_keys=True) 47 | self.assertEqual(s, '{"five": 5, "four": 4, "one": 1, "three": 3, "two": 2}') 48 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_encode_for_html.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import simplejson as json 4 | 5 | class TestEncodeForHTML(unittest.TestCase): 6 | 7 | def setUp(self): 8 | self.decoder = json.JSONDecoder() 9 | self.encoder = json.JSONEncoderForHTML() 10 | 11 | def test_basic_encode(self): 12 | self.assertEqual(r'"\u0026"', self.encoder.encode('&')) 13 | self.assertEqual(r'"\u003c"', self.encoder.encode('<')) 14 | self.assertEqual(r'"\u003e"', self.encoder.encode('>')) 15 | 16 | def test_basic_roundtrip(self): 17 | for char in '&<>': 18 | self.assertEqual( 19 | char, self.decoder.decode( 20 | self.encoder.encode(char))) 21 | 22 | def test_prevent_script_breakout(self): 23 | bad_string = '' 24 | self.assertEqual( 25 | r'"\u003c/script\u003e\u003cscript\u003e' 26 | r'alert(\"gotcha\")\u003c/script\u003e"', 27 | self.encoder.encode(bad_string)) 28 | self.assertEqual( 29 | bad_string, self.decoder.decode( 30 | self.encoder.encode(bad_string))) 31 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_errors.py: -------------------------------------------------------------------------------- 1 | import sys, pickle 2 | from unittest import TestCase 3 | 4 | import simplejson as json 5 | from simplejson.compat import u, b 6 | 7 | class TestErrors(TestCase): 8 | def test_string_keys_error(self): 9 | data = [{'a': 'A', 'b': (2, 4), 'c': 3.0, ('d',): 'D tuple'}] 10 | self.assertRaises(TypeError, json.dumps, data) 11 | 12 | def test_decode_error(self): 13 | err = None 14 | try: 15 | json.loads('{}\na\nb') 16 | except json.JSONDecodeError: 17 | err = sys.exc_info()[1] 18 | else: 19 | self.fail('Expected JSONDecodeError') 20 | self.assertEqual(err.lineno, 2) 21 | self.assertEqual(err.colno, 1) 22 | self.assertEqual(err.endlineno, 3) 23 | self.assertEqual(err.endcolno, 2) 24 | 25 | def test_scan_error(self): 26 | err = None 27 | for t in (u, b): 28 | try: 29 | json.loads(t('{"asdf": "')) 30 | except json.JSONDecodeError: 31 | err = sys.exc_info()[1] 32 | else: 33 | self.fail('Expected JSONDecodeError') 34 | self.assertEqual(err.lineno, 1) 35 | self.assertEqual(err.colno, 10) 36 | 37 | def test_error_is_pickable(self): 38 | err = None 39 | try: 40 | json.loads('{}\na\nb') 41 | except json.JSONDecodeError: 42 | err = sys.exc_info()[1] 43 | else: 44 | self.fail('Expected JSONDecodeError') 45 | s = pickle.dumps(err) 46 | e = pickle.loads(s) 47 | 48 | self.assertEqual(err.msg, e.msg) 49 | self.assertEqual(err.doc, e.doc) 50 | self.assertEqual(err.pos, e.pos) 51 | self.assertEqual(err.end, e.end) 52 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_float.py: -------------------------------------------------------------------------------- 1 | import math 2 | from unittest import TestCase 3 | from simplejson.compat import long_type, text_type 4 | import simplejson as json 5 | from simplejson.decoder import NaN, PosInf, NegInf 6 | 7 | class TestFloat(TestCase): 8 | def test_degenerates_allow(self): 9 | for inf in (PosInf, NegInf): 10 | self.assertEqual(json.loads(json.dumps(inf)), inf) 11 | # Python 2.5 doesn't have math.isnan 12 | nan = json.loads(json.dumps(NaN)) 13 | self.assertTrue((0 + nan) != nan) 14 | 15 | def test_degenerates_ignore(self): 16 | for f in (PosInf, NegInf, NaN): 17 | self.assertEqual(json.loads(json.dumps(f, ignore_nan=True)), None) 18 | 19 | def test_degenerates_deny(self): 20 | for f in (PosInf, NegInf, NaN): 21 | self.assertRaises(ValueError, json.dumps, f, allow_nan=False) 22 | 23 | def test_floats(self): 24 | for num in [1617161771.7650001, math.pi, math.pi**100, 25 | math.pi**-100, 3.1]: 26 | self.assertEqual(float(json.dumps(num)), num) 27 | self.assertEqual(json.loads(json.dumps(num)), num) 28 | self.assertEqual(json.loads(text_type(json.dumps(num))), num) 29 | 30 | def test_ints(self): 31 | for num in [1, long_type(1), 1<<32, 1<<64]: 32 | self.assertEqual(json.dumps(num), str(num)) 33 | self.assertEqual(int(json.dumps(num)), num) 34 | self.assertEqual(json.loads(json.dumps(num)), num) 35 | self.assertEqual(json.loads(text_type(json.dumps(num))), num) 36 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_item_sort_key.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import simplejson as json 4 | from operator import itemgetter 5 | 6 | class TestItemSortKey(TestCase): 7 | def test_simple_first(self): 8 | a = {'a': 1, 'c': 5, 'jack': 'jill', 'pick': 'axe', 'array': [1, 5, 6, 9], 'tuple': (83, 12, 3), 'crate': 'dog', 'zeak': 'oh'} 9 | self.assertEqual( 10 | '{"a": 1, "c": 5, "crate": "dog", "jack": "jill", "pick": "axe", "zeak": "oh", "array": [1, 5, 6, 9], "tuple": [83, 12, 3]}', 11 | json.dumps(a, item_sort_key=json.simple_first)) 12 | 13 | def test_case(self): 14 | a = {'a': 1, 'c': 5, 'Jack': 'jill', 'pick': 'axe', 'Array': [1, 5, 6, 9], 'tuple': (83, 12, 3), 'crate': 'dog', 'zeak': 'oh'} 15 | self.assertEqual( 16 | '{"Array": [1, 5, 6, 9], "Jack": "jill", "a": 1, "c": 5, "crate": "dog", "pick": "axe", "tuple": [83, 12, 3], "zeak": "oh"}', 17 | json.dumps(a, item_sort_key=itemgetter(0))) 18 | self.assertEqual( 19 | '{"a": 1, "Array": [1, 5, 6, 9], "c": 5, "crate": "dog", "Jack": "jill", "pick": "axe", "tuple": [83, 12, 3], "zeak": "oh"}', 20 | json.dumps(a, item_sort_key=lambda kv: kv[0].lower())) 21 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_iterable.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from simplejson.compat import StringIO 3 | 4 | import simplejson as json 5 | 6 | def iter_dumps(obj, **kw): 7 | return ''.join(json.JSONEncoder(**kw).iterencode(obj)) 8 | 9 | def sio_dump(obj, **kw): 10 | sio = StringIO() 11 | json.dumps(obj, **kw) 12 | return sio.getvalue() 13 | 14 | class TestIterable(unittest.TestCase): 15 | def test_iterable(self): 16 | for l in ([], [1], [1, 2], [1, 2, 3]): 17 | for opts in [{}, {'indent': 2}]: 18 | for dumps in (json.dumps, iter_dumps, sio_dump): 19 | expect = dumps(l, **opts) 20 | default_expect = dumps(sum(l), **opts) 21 | # Default is False 22 | self.assertRaises(TypeError, dumps, iter(l), **opts) 23 | self.assertRaises(TypeError, dumps, iter(l), iterable_as_array=False, **opts) 24 | self.assertEqual(expect, dumps(iter(l), iterable_as_array=True, **opts)) 25 | # Ensure that the "default" gets called 26 | self.assertEqual(default_expect, dumps(iter(l), default=sum, **opts)) 27 | self.assertEqual(default_expect, dumps(iter(l), iterable_as_array=False, default=sum, **opts)) 28 | # Ensure that the "default" does not get called 29 | self.assertEqual( 30 | expect, 31 | dumps(iter(l), iterable_as_array=True, default=sum, **opts)) 32 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_pass1.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import simplejson as json 4 | 5 | # from http://json.org/JSON_checker/test/pass1.json 6 | JSON = r''' 7 | [ 8 | "JSON Test Pattern pass1", 9 | {"object with 1 member":["array with 1 element"]}, 10 | {}, 11 | [], 12 | -42, 13 | true, 14 | false, 15 | null, 16 | { 17 | "integer": 1234567890, 18 | "real": -9876.543210, 19 | "e": 0.123456789e-12, 20 | "E": 1.234567890E+34, 21 | "": 23456789012E66, 22 | "zero": 0, 23 | "one": 1, 24 | "space": " ", 25 | "quote": "\"", 26 | "backslash": "\\", 27 | "controls": "\b\f\n\r\t", 28 | "slash": "/ & \/", 29 | "alpha": "abcdefghijklmnopqrstuvwyz", 30 | "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", 31 | "digit": "0123456789", 32 | "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", 33 | "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", 34 | "true": true, 35 | "false": false, 36 | "null": null, 37 | "array":[ ], 38 | "object":{ }, 39 | "address": "50 St. James Street", 40 | "url": "http://www.JSON.org/", 41 | "comment": "// /* */": " ", 43 | " s p a c e d " :[1,2 , 3 44 | 45 | , 46 | 47 | 4 , 5 , 6 ,7 ],"compact": [1,2,3,4,5,6,7], 48 | "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", 49 | "quotes": "" \u0022 %22 0x22 034 "", 50 | "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" 51 | : "A key can be any string" 52 | }, 53 | 0.5 ,98.6 54 | , 55 | 99.44 56 | , 57 | 58 | 1066, 59 | 1e1, 60 | 0.1e1, 61 | 1e-1, 62 | 1e00,2e+00,2e-00 63 | ,"rosebud"] 64 | ''' 65 | 66 | class TestPass1(TestCase): 67 | def test_parse(self): 68 | # test in/out equivalence and parsing 69 | res = json.loads(JSON) 70 | out = json.dumps(res) 71 | self.assertEqual(res, json.loads(out)) 72 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_pass2.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | import simplejson as json 3 | 4 | # from http://json.org/JSON_checker/test/pass2.json 5 | JSON = r''' 6 | [[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] 7 | ''' 8 | 9 | class TestPass2(TestCase): 10 | def test_parse(self): 11 | # test in/out equivalence and parsing 12 | res = json.loads(JSON) 13 | out = json.dumps(res) 14 | self.assertEqual(res, json.loads(out)) 15 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_pass3.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import simplejson as json 4 | 5 | # from http://json.org/JSON_checker/test/pass3.json 6 | JSON = r''' 7 | { 8 | "JSON Test Pattern pass3": { 9 | "The outermost value": "must be an object or array.", 10 | "In this test": "It is an object." 11 | } 12 | } 13 | ''' 14 | 15 | class TestPass3(TestCase): 16 | def test_parse(self): 17 | # test in/out equivalence and parsing 18 | res = json.loads(JSON) 19 | out = json.dumps(res) 20 | self.assertEqual(res, json.loads(out)) 21 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_raw_json.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import simplejson as json 3 | 4 | dct1 = { 5 | 'key1': 'value1' 6 | } 7 | 8 | dct2 = { 9 | 'key2': 'value2', 10 | 'd1': dct1 11 | } 12 | 13 | dct3 = { 14 | 'key2': 'value2', 15 | 'd1': json.dumps(dct1) 16 | } 17 | 18 | dct4 = { 19 | 'key2': 'value2', 20 | 'd1': json.RawJSON(json.dumps(dct1)) 21 | } 22 | 23 | 24 | class TestRawJson(unittest.TestCase): 25 | 26 | def test_normal_str(self): 27 | self.assertNotEqual(json.dumps(dct2), json.dumps(dct3)) 28 | 29 | def test_raw_json_str(self): 30 | self.assertEqual(json.dumps(dct2), json.dumps(dct4)) 31 | self.assertEqual(dct2, json.loads(json.dumps(dct4))) 32 | 33 | def test_list(self): 34 | self.assertEqual( 35 | json.dumps([dct2]), 36 | json.dumps([json.RawJSON(json.dumps(dct2))])) 37 | self.assertEqual( 38 | [dct2], 39 | json.loads(json.dumps([json.RawJSON(json.dumps(dct2))]))) 40 | 41 | def test_direct(self): 42 | self.assertEqual( 43 | json.dumps(dct2), 44 | json.dumps(json.RawJSON(json.dumps(dct2)))) 45 | self.assertEqual( 46 | dct2, 47 | json.loads(json.dumps(json.RawJSON(json.dumps(dct2))))) 48 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_recursion.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import simplejson as json 4 | 5 | class JSONTestObject: 6 | pass 7 | 8 | 9 | class RecursiveJSONEncoder(json.JSONEncoder): 10 | recurse = False 11 | def default(self, o): 12 | if o is JSONTestObject: 13 | if self.recurse: 14 | return [JSONTestObject] 15 | else: 16 | return 'JSONTestObject' 17 | return json.JSONEncoder.default(o) 18 | 19 | 20 | class TestRecursion(TestCase): 21 | def test_listrecursion(self): 22 | x = [] 23 | x.append(x) 24 | try: 25 | json.dumps(x) 26 | except ValueError: 27 | pass 28 | else: 29 | self.fail("didn't raise ValueError on list recursion") 30 | x = [] 31 | y = [x] 32 | x.append(y) 33 | try: 34 | json.dumps(x) 35 | except ValueError: 36 | pass 37 | else: 38 | self.fail("didn't raise ValueError on alternating list recursion") 39 | y = [] 40 | x = [y, y] 41 | # ensure that the marker is cleared 42 | json.dumps(x) 43 | 44 | def test_dictrecursion(self): 45 | x = {} 46 | x["test"] = x 47 | try: 48 | json.dumps(x) 49 | except ValueError: 50 | pass 51 | else: 52 | self.fail("didn't raise ValueError on dict recursion") 53 | x = {} 54 | y = {"a": x, "b": x} 55 | # ensure that the marker is cleared 56 | json.dumps(y) 57 | 58 | def test_defaultrecursion(self): 59 | enc = RecursiveJSONEncoder() 60 | self.assertEqual(enc.encode(JSONTestObject), '"JSONTestObject"') 61 | enc.recurse = True 62 | try: 63 | enc.encode(JSONTestObject) 64 | except ValueError: 65 | pass 66 | else: 67 | self.fail("didn't raise ValueError on default recursion") 68 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_separators.py: -------------------------------------------------------------------------------- 1 | import textwrap 2 | from unittest import TestCase 3 | 4 | import simplejson as json 5 | 6 | 7 | class TestSeparators(TestCase): 8 | def test_separators(self): 9 | h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', 10 | {'nifty': 87}, {'field': 'yes', 'morefield': False} ] 11 | 12 | expect = textwrap.dedent("""\ 13 | [ 14 | [ 15 | "blorpie" 16 | ] , 17 | [ 18 | "whoops" 19 | ] , 20 | [] , 21 | "d-shtaeou" , 22 | "d-nthiouh" , 23 | "i-vhbjkhnth" , 24 | { 25 | "nifty" : 87 26 | } , 27 | { 28 | "field" : "yes" , 29 | "morefield" : false 30 | } 31 | ]""") 32 | 33 | 34 | d1 = json.dumps(h) 35 | d2 = json.dumps(h, indent=' ', sort_keys=True, separators=(' ,', ' : ')) 36 | 37 | h1 = json.loads(d1) 38 | h2 = json.loads(d2) 39 | 40 | self.assertEqual(h1, h) 41 | self.assertEqual(h2, h) 42 | self.assertEqual(d2, expect) 43 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_speedups.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import unittest 3 | from unittest import TestCase 4 | 5 | from simplejson import encoder, scanner 6 | 7 | 8 | def has_speedups(): 9 | return encoder.c_make_encoder is not None 10 | 11 | 12 | def skip_if_speedups_missing(func): 13 | def wrapper(*args, **kwargs): 14 | if not has_speedups(): 15 | if hasattr(unittest, 'SkipTest'): 16 | raise unittest.SkipTest("C Extension not available") 17 | else: 18 | sys.stdout.write("C Extension not available") 19 | return 20 | return func(*args, **kwargs) 21 | 22 | return wrapper 23 | 24 | 25 | class TestDecode(TestCase): 26 | @skip_if_speedups_missing 27 | def test_make_scanner(self): 28 | self.assertRaises(AttributeError, scanner.c_make_scanner, 1) 29 | 30 | @skip_if_speedups_missing 31 | def test_make_encoder(self): 32 | self.assertRaises( 33 | TypeError, 34 | encoder.c_make_encoder, 35 | None, 36 | ("\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7" 37 | "\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75"), 38 | None 39 | ) 40 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_str_subclass.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import simplejson 4 | from simplejson.compat import text_type, u 5 | 6 | # Tests for issue demonstrated in https://github.com/simplejson/simplejson/issues/144 7 | class WonkyTextSubclass(text_type): 8 | def __getslice__(self, start, end): 9 | return self.__class__('not what you wanted!') 10 | 11 | class TestStrSubclass(TestCase): 12 | def test_dump_load(self): 13 | for s in ['', '"hello"', 'text', u('\u005c')]: 14 | self.assertEqual( 15 | s, 16 | simplejson.loads(simplejson.dumps(WonkyTextSubclass(s)))) 17 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_subclass.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | import simplejson as json 3 | 4 | from decimal import Decimal 5 | 6 | class AlternateInt(int): 7 | def __repr__(self): 8 | return 'invalid json' 9 | __str__ = __repr__ 10 | 11 | 12 | class AlternateFloat(float): 13 | def __repr__(self): 14 | return 'invalid json' 15 | __str__ = __repr__ 16 | 17 | 18 | # class AlternateDecimal(Decimal): 19 | # def __repr__(self): 20 | # return 'invalid json' 21 | 22 | 23 | class TestSubclass(TestCase): 24 | def test_int(self): 25 | self.assertEqual(json.dumps(AlternateInt(1)), '1') 26 | self.assertEqual(json.dumps(AlternateInt(-1)), '-1') 27 | self.assertEqual(json.loads(json.dumps({AlternateInt(1): 1})), {'1': 1}) 28 | 29 | def test_float(self): 30 | self.assertEqual(json.dumps(AlternateFloat(1.0)), '1.0') 31 | self.assertEqual(json.dumps(AlternateFloat(-1.0)), '-1.0') 32 | self.assertEqual(json.loads(json.dumps({AlternateFloat(1.0): 1})), {'1.0': 1}) 33 | 34 | # NOTE: Decimal subclasses are not supported as-is 35 | # def test_decimal(self): 36 | # self.assertEqual(json.dumps(AlternateDecimal('1.0')), '1.0') 37 | # self.assertEqual(json.dumps(AlternateDecimal('-1.0')), '-1.0') 38 | -------------------------------------------------------------------------------- /lib/simplejson/tests/test_tuple.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from simplejson.compat import StringIO 4 | import simplejson as json 5 | 6 | class TestTuples(unittest.TestCase): 7 | def test_tuple_array_dumps(self): 8 | t = (1, 2, 3) 9 | expect = json.dumps(list(t)) 10 | # Default is True 11 | self.assertEqual(expect, json.dumps(t)) 12 | self.assertEqual(expect, json.dumps(t, tuple_as_array=True)) 13 | self.assertRaises(TypeError, json.dumps, t, tuple_as_array=False) 14 | # Ensure that the "default" does not get called 15 | self.assertEqual(expect, json.dumps(t, default=repr)) 16 | self.assertEqual(expect, json.dumps(t, tuple_as_array=True, 17 | default=repr)) 18 | # Ensure that the "default" gets called 19 | self.assertEqual( 20 | json.dumps(repr(t)), 21 | json.dumps(t, tuple_as_array=False, default=repr)) 22 | 23 | def test_tuple_array_dump(self): 24 | t = (1, 2, 3) 25 | expect = json.dumps(list(t)) 26 | # Default is True 27 | sio = StringIO() 28 | json.dump(t, sio) 29 | self.assertEqual(expect, sio.getvalue()) 30 | sio = StringIO() 31 | json.dump(t, sio, tuple_as_array=True) 32 | self.assertEqual(expect, sio.getvalue()) 33 | self.assertRaises(TypeError, json.dump, t, StringIO(), 34 | tuple_as_array=False) 35 | # Ensure that the "default" does not get called 36 | sio = StringIO() 37 | json.dump(t, sio, default=repr) 38 | self.assertEqual(expect, sio.getvalue()) 39 | sio = StringIO() 40 | json.dump(t, sio, tuple_as_array=True, default=repr) 41 | self.assertEqual(expect, sio.getvalue()) 42 | # Ensure that the "default" gets called 43 | sio = StringIO() 44 | json.dump(t, sio, tuple_as_array=False, default=repr) 45 | self.assertEqual( 46 | json.dumps(repr(t)), 47 | sio.getvalue()) 48 | -------------------------------------------------------------------------------- /lib/simplejson/tool.py: -------------------------------------------------------------------------------- 1 | r"""Command-line tool to validate and pretty-print JSON 2 | 3 | Usage:: 4 | 5 | $ echo '{"json":"obj"}' | python -m simplejson.tool 6 | { 7 | "json": "obj" 8 | } 9 | $ echo '{ 1.2:3.4}' | python -m simplejson.tool 10 | Expecting property name: line 1 column 2 (char 2) 11 | 12 | """ 13 | from __future__ import with_statement 14 | import sys 15 | import lib.simplejson as json 16 | 17 | def main(): 18 | if len(sys.argv) == 1: 19 | infile = sys.stdin 20 | outfile = sys.stdout 21 | elif len(sys.argv) == 2: 22 | infile = open(sys.argv[1], 'r') 23 | outfile = sys.stdout 24 | elif len(sys.argv) == 3: 25 | infile = open(sys.argv[1], 'r') 26 | outfile = open(sys.argv[2], 'w') 27 | else: 28 | raise SystemExit(sys.argv[0] + " [infile [outfile]]") 29 | with infile: 30 | try: 31 | obj = json.load(infile, 32 | object_pairs_hook=json.OrderedDict, 33 | use_decimal=True) 34 | except ValueError: 35 | raise SystemExit(sys.exc_info()[1]) 36 | with outfile: 37 | json.dump(obj, outfile, sort_keys=True, indent=' ', use_decimal=True) 38 | outfile.write('\n') 39 | 40 | 41 | if __name__ == '__main__': 42 | main() 43 | -------------------------------------------------------------------------------- /lib/tinytag.note: -------------------------------------------------------------------------------- 1 | This version of TinyTag included with lazylibrarian 2 | has "composer" field added as we need it for audiobooks 3 | and m4b added as equivalent filetype to m4a 4 | and a block on the end to allow testing from commandline 5 | 6 | if __name__ == '__main__': 7 | if len(sys.argv) < 2 or '-?' in sys.argv: 8 | print("Give me a filename") 9 | else: 10 | id3 = TinyTag.get(sys.argv[1]) 11 | print('Artist :', id3.artist) 12 | print('Album :', id3.album) 13 | print('AlbumArtist :', id3.albumartist) 14 | print('Composer :', id3.composer) 15 | print('Title :', id3.title) 16 | print('Track :', id3.track) 17 | print('EndTrack :', id3.track_total) 18 | -------------------------------------------------------------------------------- /lib/unrar/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (C) 2012 Matias Bordese 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | __author__ = 'Matias Bordese' 19 | __email__ = 'mbordese@gmail.com' 20 | __version__ = '0.3' 21 | 22 | VERSION = __version__ 23 | -------------------------------------------------------------------------------- /lib/unrar/constants.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (C) 2012 Matias Bordese 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | 18 | 19 | # Success result 20 | SUCCESS = 0 21 | 22 | # 23 | # Open Modes 24 | # 25 | 26 | # headers only 27 | RAR_OM_LIST = 0 28 | # testing and extracting 29 | RAR_OM_EXTRACT = 1 30 | # headers only, include splitted volumes 31 | RAR_OM_LIST_INCSPLIT = 2 32 | 33 | # 34 | # Process file operations 35 | # 36 | 37 | RAR_SKIP = 0 38 | RAR_TEST = 1 39 | RAR_EXTRACT = 2 40 | RAR_CANCEL_EXTRACT = -1 41 | 42 | # 43 | # Errors 44 | # 45 | 46 | # End of archive 47 | ERAR_END_ARCHIVE = 10 48 | # Not enough memory to initialize data structures 49 | ERAR_NO_MEMORY = 11 50 | # Archive header broken 51 | ERAR_BAD_DATA = 12 52 | # File is not valid RAR archive 53 | ERAR_BAD_ARCHIVE = 13 54 | # Unknown encryption used for archive headers 55 | ERAR_UNKNOWN_FORMAT = 14 56 | # Archive/Volume open error 57 | ERAR_EOPEN = 15 58 | # File create error 59 | ERAR_ECREATE = 16 60 | # Archive/File close error 61 | ERAR_ECLOSE = 17 62 | # Read error 63 | ERAR_EREAD = 18 64 | # Write error 65 | ERAR_EWRITE = 19 66 | # Buffer too small, comments not completely read 67 | ERAR_SMALL_BUF = 20 68 | # Unknown error 69 | ERAR_UNKNOWN = 21 70 | # Missing password error 71 | ERAR_MISSING_PASSWORD = 22 72 | 73 | # 74 | # Comments state 75 | # 76 | 77 | # comments not present 78 | RAR_NO_COMMENTS = 0 79 | # Comments read completely 80 | RAR_COMMENTS_SUCCESS = 1 81 | 82 | 83 | # 84 | # Host OS 85 | # 86 | 87 | RAR_DOS = 0 88 | RAR_OS2 = 1 89 | RAR_WIN = 2 90 | RAR_UNIX = 3 91 | 92 | 93 | # 94 | # Callback messages 95 | # 96 | 97 | UCM_CHANGEVOLUME = 0 98 | UCM_PROCESSDATA = 1 99 | UCM_NEEDPASSWORD = 2 100 | UCM_CHANGEVOLUMEW = 3 101 | UCM_NEEDPASSWORDW = 4 102 | 103 | # 104 | # Change volume callback message 105 | # 106 | RAR_VOL_ASK = 0 107 | RAR_VOL_NOTIFY = 1 108 | -------------------------------------------------------------------------------- /lib/webencodings/mklabels.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | webencodings.mklabels 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Regenarate the webencodings.labels module. 7 | 8 | :copyright: Copyright 2012 by Simon Sapin 9 | :license: BSD, see LICENSE for details. 10 | 11 | """ 12 | 13 | import json 14 | try: 15 | from urllib import urlopen 16 | except ImportError: 17 | from urllib.request import urlopen 18 | 19 | 20 | def assert_lower(string): 21 | assert string == string.lower() 22 | return string 23 | 24 | 25 | def generate(url): 26 | parts = ['''\ 27 | """ 28 | 29 | webencodings.labels 30 | ~~~~~~~~~~~~~~~~~~~ 31 | 32 | Map encoding labels to their name. 33 | 34 | :copyright: Copyright 2012 by Simon Sapin 35 | :license: BSD, see LICENSE for details. 36 | 37 | """ 38 | 39 | # XXX Do not edit! 40 | # This file is automatically generated by mklabels.py 41 | 42 | LABELS = { 43 | '''] 44 | labels = [ 45 | (repr(assert_lower(label)).lstrip('u'), 46 | repr(encoding['name']).lstrip('u')) 47 | for category in json.loads(urlopen(url).read().decode('ascii')) 48 | for encoding in category['encodings'] 49 | for label in encoding['labels']] 50 | max_len = max(len(label) for label, name in labels) 51 | parts.extend( 52 | ' %s:%s %s,\n' % (label, ' ' * (max_len - len(label)), name) 53 | for label, name in labels) 54 | parts.append('}') 55 | return ''.join(parts) 56 | 57 | 58 | if __name__ == '__main__': 59 | print(generate('http://encoding.spec.whatwg.org/encodings.json')) 60 | -------------------------------------------------------------------------------- /lib3/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/lib3/__init__.py -------------------------------------------------------------------------------- /mako/__init__.py: -------------------------------------------------------------------------------- 1 | # mako/__init__.py 2 | # Copyright (C) 2006-2015 the Mako authors and contributors 3 | # 4 | # This module is part of Mako and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | 8 | __version__ = '1.0.3' 9 | -------------------------------------------------------------------------------- /mako/cmd.py: -------------------------------------------------------------------------------- 1 | # mako/cmd.py 2 | # Copyright (C) 2006-2015 the Mako authors and contributors 3 | # 4 | # This module is part of Mako and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | from argparse import ArgumentParser 7 | from os.path import isfile, dirname 8 | import sys 9 | from mako.template import Template 10 | from mako.lookup import TemplateLookup 11 | from mako import exceptions 12 | 13 | 14 | def varsplit(var): 15 | if "=" not in var: 16 | return (var, "") 17 | return var.split("=", 1) 18 | 19 | 20 | def _exit(): 21 | sys.stderr.write(exceptions.text_error_template().render()) 22 | sys.exit(1) 23 | 24 | 25 | def cmdline(argv=None): 26 | 27 | parser = ArgumentParser("usage: %prog [FILENAME]") 28 | parser.add_argument( 29 | "--var", default=[], action="append", 30 | help="variable (can be used multiple times, use name=value)") 31 | parser.add_argument( 32 | "--template-dir", default=[], action="append", 33 | help="Directory to use for template lookup (multiple " 34 | "directories may be provided). If not given then if the " 35 | "template is read from stdin, the value defaults to be " 36 | "the current directory, otherwise it defaults to be the " 37 | "parent directory of the file provided.") 38 | parser.add_argument('input', nargs='?', default='-') 39 | 40 | options = parser.parse_args(argv) 41 | if options.input == '-': 42 | lookup_dirs = options.template_dir or ["."] 43 | lookup = TemplateLookup(lookup_dirs) 44 | try: 45 | template = Template(sys.stdin.read(), lookup=lookup) 46 | except: 47 | _exit() 48 | else: 49 | filename = options.input 50 | if not isfile(filename): 51 | raise SystemExit("error: can't find %s" % filename) 52 | lookup_dirs = options.template_dir or [dirname(filename)] 53 | lookup = TemplateLookup(lookup_dirs) 54 | try: 55 | template = Template(filename=filename, lookup=lookup) 56 | except: 57 | _exit() 58 | 59 | kw = dict([varsplit(var) for var in options.var]) 60 | try: 61 | print(template.render(**kw)) 62 | except: 63 | _exit() 64 | 65 | 66 | if __name__ == "__main__": 67 | cmdline() 68 | -------------------------------------------------------------------------------- /mako/ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DobyTang/LazyLibrarian/45d4f24da214507c6913bde47efe063688d6bb84/mako/ext/__init__.py -------------------------------------------------------------------------------- /mako/ext/autohandler.py: -------------------------------------------------------------------------------- 1 | # ext/autohandler.py 2 | # Copyright (C) 2006-2015 the Mako authors and contributors 3 | # 4 | # This module is part of Mako and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """adds autohandler functionality to Mako templates. 8 | 9 | requires that the TemplateLookup class is used with templates. 10 | 11 | usage: 12 | 13 | <%! 14 | from mako.ext.autohandler import autohandler 15 | %> 16 | <%inherit file="${autohandler(template, context)}"/> 17 | 18 | 19 | or with custom autohandler filename: 20 | 21 | <%! 22 | from mako.ext.autohandler import autohandler 23 | %> 24 | <%inherit file="${autohandler(template, context, name='somefilename')}"/> 25 | 26 | """ 27 | 28 | import posixpath 29 | import os 30 | import re 31 | 32 | 33 | def autohandler(template, context, name='autohandler'): 34 | lookup = context.lookup 35 | _template_uri = template.module._template_uri 36 | if not lookup.filesystem_checks: 37 | try: 38 | return lookup._uri_cache[(autohandler, _template_uri, name)] 39 | except KeyError: 40 | pass 41 | 42 | tokens = re.findall(r'([^/]+)', posixpath.dirname(_template_uri)) + [name] 43 | while len(tokens): 44 | path = '/' + '/'.join(tokens) 45 | if path != _template_uri and _file_exists(lookup, path): 46 | if not lookup.filesystem_checks: 47 | return lookup._uri_cache.setdefault( 48 | (autohandler, _template_uri, name), path) 49 | else: 50 | return path 51 | if len(tokens) == 1: 52 | break 53 | tokens[-2:] = [name] 54 | 55 | if not lookup.filesystem_checks: 56 | return lookup._uri_cache.setdefault( 57 | (autohandler, _template_uri, name), None) 58 | else: 59 | return None 60 | 61 | 62 | def _file_exists(lookup, path): 63 | psub = re.sub(r'^/', '', path) 64 | for d in lookup.directories: 65 | if os.path.exists(d + '/' + psub): 66 | return True 67 | else: 68 | return False 69 | -------------------------------------------------------------------------------- /mako/ext/babelplugin.py: -------------------------------------------------------------------------------- 1 | # ext/babelplugin.py 2 | # Copyright (C) 2006-2015 the Mako authors and contributors 3 | # 4 | # This module is part of Mako and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """gettext message extraction via Babel: http://babel.edgewall.org/""" 8 | from babel.messages.extract import extract_python 9 | from mako.ext.extract import MessageExtractor 10 | 11 | 12 | class BabelMakoExtractor(MessageExtractor): 13 | 14 | def __init__(self, keywords, comment_tags, options): 15 | self.keywords = keywords 16 | self.options = options 17 | self.config = { 18 | 'comment-tags': u' '.join(comment_tags), 19 | 'encoding': options.get('input_encoding', 20 | options.get('encoding', None)), 21 | } 22 | super(BabelMakoExtractor, self).__init__() 23 | 24 | def __call__(self, fileobj): 25 | return self.process_file(fileobj) 26 | 27 | def process_python(self, code, code_lineno, translator_strings): 28 | comment_tags = self.config['comment-tags'] 29 | for lineno, funcname, messages, python_translator_comments \ 30 | in extract_python(code, 31 | self.keywords, comment_tags, self.options): 32 | yield (code_lineno + (lineno - 1), funcname, messages, 33 | translator_strings + python_translator_comments) 34 | 35 | 36 | def extract(fileobj, keywords, comment_tags, options): 37 | """Extract messages from Mako templates. 38 | 39 | :param fileobj: the file-like object the messages should be extracted from 40 | :param keywords: a list of keywords (i.e. function names) that should be 41 | recognized as translation functions 42 | :param comment_tags: a list of translator tags to search for and include 43 | in the results 44 | :param options: a dictionary of additional options (optional) 45 | :return: an iterator over ``(lineno, funcname, message, comments)`` tuples 46 | :rtype: ``iterator`` 47 | """ 48 | extractor = BabelMakoExtractor(keywords, comment_tags, options) 49 | for message in extractor(fileobj): 50 | yield message 51 | -------------------------------------------------------------------------------- /mako/ext/beaker_cache.py: -------------------------------------------------------------------------------- 1 | """Provide a :class:`.CacheImpl` for the Beaker caching system.""" 2 | 3 | from mako import exceptions 4 | 5 | from mako.cache import CacheImpl 6 | 7 | try: 8 | from beaker import cache as beaker_cache 9 | except: 10 | has_beaker = False 11 | else: 12 | has_beaker = True 13 | 14 | _beaker_cache = None 15 | 16 | 17 | class BeakerCacheImpl(CacheImpl): 18 | 19 | """A :class:`.CacheImpl` provided for the Beaker caching system. 20 | 21 | This plugin is used by default, based on the default 22 | value of ``'beaker'`` for the ``cache_impl`` parameter of the 23 | :class:`.Template` or :class:`.TemplateLookup` classes. 24 | 25 | """ 26 | 27 | def __init__(self, cache): 28 | if not has_beaker: 29 | raise exceptions.RuntimeException( 30 | "Can't initialize Beaker plugin; Beaker is not installed.") 31 | global _beaker_cache 32 | if _beaker_cache is None: 33 | if 'manager' in cache.template.cache_args: 34 | _beaker_cache = cache.template.cache_args['manager'] 35 | else: 36 | _beaker_cache = beaker_cache.CacheManager() 37 | super(BeakerCacheImpl, self).__init__(cache) 38 | 39 | def _get_cache(self, **kw): 40 | expiretime = kw.pop('timeout', None) 41 | if 'dir' in kw: 42 | kw['data_dir'] = kw.pop('dir') 43 | elif self.cache.template.module_directory: 44 | kw['data_dir'] = self.cache.template.module_directory 45 | 46 | if 'manager' in kw: 47 | kw.pop('manager') 48 | 49 | if kw.get('type') == 'memcached': 50 | kw['type'] = 'ext:memcached' 51 | 52 | if 'region' in kw: 53 | region = kw.pop('region') 54 | cache = _beaker_cache.get_cache_region(self.cache.id, region, **kw) 55 | else: 56 | cache = _beaker_cache.get_cache(self.cache.id, **kw) 57 | cache_args = {'starttime': self.cache.starttime} 58 | if expiretime: 59 | cache_args['expiretime'] = expiretime 60 | return cache, cache_args 61 | 62 | def get_or_create(self, key, creation_function, **kw): 63 | cache, kw = self._get_cache(**kw) 64 | return cache.get(key, createfunc=creation_function, **kw) 65 | 66 | def put(self, key, value, **kw): 67 | cache, kw = self._get_cache(**kw) 68 | cache.put(key, value, **kw) 69 | 70 | def get(self, key, **kw): 71 | cache, kw = self._get_cache(**kw) 72 | return cache.get(key, **kw) 73 | 74 | def invalidate(self, key, **kw): 75 | cache, kw = self._get_cache(**kw) 76 | cache.remove_value(key, **kw) 77 | -------------------------------------------------------------------------------- /mako/ext/linguaplugin.py: -------------------------------------------------------------------------------- 1 | import io 2 | from lingua.extractors import Extractor 3 | from lingua.extractors import Message 4 | from lingua.extractors import get_extractor 5 | from mako.ext.extract import MessageExtractor 6 | from mako import compat 7 | 8 | 9 | class LinguaMakoExtractor(Extractor, MessageExtractor): 10 | 11 | '''Mako templates''' 12 | extensions = ['.mako'] 13 | default_config = { 14 | 'encoding': 'utf-8', 15 | 'comment-tags': '', 16 | } 17 | 18 | def __call__(self, filename, options, fileobj=None): 19 | self.options = options 20 | self.filename = filename 21 | self.python_extractor = get_extractor('x.py') 22 | if fileobj is None: 23 | fileobj = open(filename, 'rb') 24 | return self.process_file(fileobj) 25 | 26 | def process_python(self, code, code_lineno, translator_strings): 27 | source = code.getvalue().strip() 28 | if source.endswith(compat.b(':')): 29 | if source in (compat.b('try:'), compat.b('else:')) or source.startswith(compat.b('except')): 30 | source = compat.b('') # Ignore try/except and else 31 | elif source.startswith(compat.b('elif')): 32 | source = source[2:] # Replace "elif" with "if" 33 | source += compat.b('pass') 34 | code = io.BytesIO(source) 35 | for msg in self.python_extractor( 36 | self.filename, self.options, code, code_lineno -1): 37 | if translator_strings: 38 | msg = Message(msg.msgctxt, msg.msgid, msg.msgid_plural, 39 | msg.flags, 40 | compat.u(' ').join( 41 | translator_strings + [msg.comment]), 42 | msg.tcomment, msg.location) 43 | yield msg 44 | -------------------------------------------------------------------------------- /mako/ext/preprocessors.py: -------------------------------------------------------------------------------- 1 | # ext/preprocessors.py 2 | # Copyright (C) 2006-2015 the Mako authors and contributors 3 | # 4 | # This module is part of Mako and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | """preprocessing functions, used with the 'preprocessor' 8 | argument on Template, TemplateLookup""" 9 | 10 | import re 11 | 12 | 13 | def convert_comments(text): 14 | """preprocess old style comments. 15 | 16 | example: 17 | 18 | from mako.ext.preprocessors import convert_comments 19 | t = Template(..., preprocessor=convert_comments)""" 20 | return re.sub(r'(?<=\n)\s*#[^#]', "##", text) 21 | -------------------------------------------------------------------------------- /mako/ext/turbogears.py: -------------------------------------------------------------------------------- 1 | # ext/turbogears.py 2 | # Copyright (C) 2006-2015 the Mako authors and contributors 3 | # 4 | # This module is part of Mako and is released under 5 | # the MIT License: http://www.opensource.org/licenses/mit-license.php 6 | 7 | from mako import compat 8 | from mako.lookup import TemplateLookup 9 | from mako.template import Template 10 | 11 | 12 | class TGPlugin(object): 13 | 14 | """TurboGears compatible Template Plugin.""" 15 | 16 | def __init__(self, extra_vars_func=None, options=None, extension='mak'): 17 | self.extra_vars_func = extra_vars_func 18 | self.extension = extension 19 | if not options: 20 | options = {} 21 | 22 | # Pull the options out and initialize the lookup 23 | lookup_options = {} 24 | for k, v in options.items(): 25 | if k.startswith('mako.'): 26 | lookup_options[k[5:]] = v 27 | elif k in ['directories', 'filesystem_checks', 'module_directory']: 28 | lookup_options[k] = v 29 | self.lookup = TemplateLookup(**lookup_options) 30 | 31 | self.tmpl_options = {} 32 | # transfer lookup args to template args, based on those available 33 | # in getargspec 34 | for kw in compat.inspect_getargspec(Template.__init__)[0]: 35 | if kw in lookup_options: 36 | self.tmpl_options[kw] = lookup_options[kw] 37 | 38 | def load_template(self, templatename, template_string=None): 39 | """Loads a template from a file or a string""" 40 | if template_string is not None: 41 | return Template(template_string, **self.tmpl_options) 42 | # Translate TG dot notation to normal / template path 43 | if '/' not in templatename: 44 | templatename = '/' + templatename.replace('.', '/') + '.' +\ 45 | self.extension 46 | 47 | # Lookup template 48 | return self.lookup.get_template(templatename) 49 | 50 | def render(self, info, format="html", fragment=False, template=None): 51 | if isinstance(template, compat.string_types): 52 | template = self.load_template(template) 53 | 54 | # Load extra vars func if provided 55 | if self.extra_vars_func: 56 | info.update(self.extra_vars_func()) 57 | 58 | return template.render(**info) 59 | --------------------------------------------------------------------------------