├── .travis.yml ├── LICENSE.txt ├── MANIFEST.in ├── README.rst ├── docs ├── Makefile ├── conf.py ├── download.rst ├── examples.rst ├── index.rst ├── install.rst ├── overview.rst ├── reference.rst ├── test.rst └── tutorial.rst ├── examples ├── account_infos.py ├── base.py ├── check_remote_upload.py ├── convert_file.py ├── delete_file.py ├── download_full.py ├── download_link.py ├── download_ticket.py ├── file_info.py ├── list_folder.py ├── remote_upload.py ├── rename_file.py ├── rename_folder.py ├── running_converts.py ├── splash_image.py ├── upload_file.py └── upload_link.py ├── openload ├── __init__.py ├── api_exceptions.py └── openload.py ├── requirements-doc.txt ├── setup.cfg ├── setup.py └── tests ├── __init__.py ├── file.txt └── test_openload.py /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: python 3 | python: 4 | - "2.7" 5 | - "3.4" 6 | - "3.5" 7 | - "3.6" 8 | - "3.7" 9 | 10 | install: 11 | - pip install . 12 | - pip install pytest 13 | 14 | script: 15 | - pytest -k 'not test_list_folder and not test_upload_file_with_folder and not test_running_conversions_with_folder' 16 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 mohan3d 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # Include the license file 2 | include LICENSE.txt -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | PyOpenload |StarButton| 2 | ======================= 3 | 4 | python wrapper for `Openload.co`_ `API`_. 5 | 6 | |travis| |pypi| |format| |CodacyBadge| |license| 7 | 8 | Install 9 | ------- 10 | 11 | .. code-block:: bash 12 | 13 | $ pip install pyopenload 14 | 15 | 16 | Usage 17 | ----- 18 | 19 | All `API`_ features are implemented. 20 | 21 | **Retrieve account info** 22 | 23 | .. code:: python 24 | 25 | from openload import OpenLoad 26 | 27 | ol = OpenLoad('login', 'key') 28 | 29 | account_info = ol.account_info() 30 | print(account_info) 31 | 32 | 33 | **Upload file** 34 | 35 | .. code:: python 36 | 37 | from openload import OpenLoad 38 | 39 | ol = OpenLoad('login', 'key') 40 | 41 | uploaded_file_info = ol.upload_file('/home/username/file.txt') 42 | print(uploaded_file_info) 43 | 44 | 45 | **Retrieve file info** 46 | 47 | .. code:: python 48 | 49 | from openload import OpenLoad 50 | 51 | ol = OpenLoad('login', 'key') 52 | 53 | # Random file id. 54 | file_id = 'YMTqhQAuzVX' 55 | 56 | file_info = ol.file_info(file_id) 57 | print(file_info) 58 | 59 | Documentation 60 | ------------- 61 | 62 | documentation is available at https://pyopenload.readthedocs.io/. 63 | 64 | .. _Openload.co: https://openload.co 65 | .. _API: https://openload.co/api 66 | 67 | .. |StarButton| image:: https://img.shields.io/github/stars/mohan3d/pyopenload.svg?style=social&label=Star&maxAge=3600 68 | :target: https://github.com/mohan3d/PyOpenload 69 | 70 | .. |pypi| image:: https://img.shields.io/pypi/v/pyopenload.svg?maxAge=3600&style=flat-square 71 | :target: https://pypi.python.org/pypi/pyopenload 72 | 73 | .. |format| image:: https://img.shields.io/pypi/format/pyopenload.svg?maxAge=3600&style=flat-square 74 | :target: https://pypi.python.org/pypi/pyopenload 75 | 76 | .. |CodacyBadge| image:: https://img.shields.io/codacy/grade/42d0f198fcbe43daae71e21b6a3540fe.svg?maxAge=3600&style=flat-square 77 | :target: https://www.codacy.com/app/mohan3d94/PyOpenload?utm_source=github.com&utm_medium=referral&utm_content=mohan3d/PyOpenload&utm_campaign=badger 78 | 79 | .. |license| image:: https://img.shields.io/pypi/l/pyopenload.svg?maxAge=3600&style=flat-square 80 | :target: https://choosealicense.com/licenses/mit/ 81 | 82 | .. |travis| image:: https://img.shields.io/travis/mohan3d/PyOpenload.svg?maxAge=3600&style=flat-square 83 | :target: https://travis-ci.org/mohan3d/PyOpenload 84 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = python -msphinx 7 | SPHINXPROJ = PyOpenload 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | # 5 | # PyOpenload documentation build configuration file, created by 6 | # sphinx-quickstart on Wed Aug 9 22:03:50 2017. 7 | # 8 | # This file is execfile()d with the current directory set to its 9 | # containing dir. 10 | # 11 | # Note that not all possible configuration values are present in this 12 | # autogenerated file. 13 | # 14 | # All configuration values have a default; values that are commented out 15 | # serve to show the default. 16 | 17 | # If extensions (or modules to document with autodoc) are in another directory, 18 | # add these directories to sys.path here. If the directory is relative to the 19 | # documentation root, use os.path.abspath to make it absolute, like shown here. 20 | # 21 | # import os 22 | # import sys 23 | # sys.path.insert(0, os.path.abspath('.')) 24 | import os 25 | import sys 26 | 27 | import sphinx_rtd_theme 28 | 29 | sys.path.insert(0, os.path.abspath('..')) 30 | 31 | # -- General configuration ------------------------------------------------ 32 | 33 | # If your documentation needs a minimal Sphinx version, state it here. 34 | # 35 | # needs_sphinx = '1.0' 36 | 37 | # Add any Sphinx extension module names here, as strings. They can be 38 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 39 | # ones. 40 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon'] 41 | 42 | # Add any paths that contain templates here, relative to this directory. 43 | templates_path = ['_templates'] 44 | 45 | # The suffix(es) of source filenames. 46 | # You can specify multiple suffix as a list of string: 47 | # 48 | # source_suffix = ['.rst', '.md'] 49 | source_suffix = '.rst' 50 | 51 | # The master toctree document. 52 | master_doc = 'index' 53 | 54 | # General information about the project. 55 | project = 'PyOpenload' 56 | copyright = '2017, Mohaned Magdy' 57 | author = 'Mohaned Magdy' 58 | 59 | # The version info for the project you're documenting, acts as replacement for 60 | # |version| and |release|, also used in various other places throughout the 61 | # built documents. 62 | # 63 | # The short X.Y version. 64 | version = '0.4' 65 | # The full version, including alpha/beta/rc tags. 66 | release = '0.4' 67 | 68 | # The language for content autogenerated by Sphinx. Refer to documentation 69 | # for a list of supported languages. 70 | # 71 | # This is also used if you do content translation via gettext catalogs. 72 | # Usually you set "language" from the command line for these cases. 73 | language = None 74 | 75 | # List of patterns, relative to source directory, that match files and 76 | # directories to ignore when looking for source files. 77 | # This patterns also effect to html_static_path and html_extra_path 78 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 79 | 80 | # The name of the Pygments (syntax highlighting) style to use. 81 | pygments_style = 'sphinx' 82 | 83 | # If true, `todo` and `todoList` produce output, else they produce nothing. 84 | todo_include_todos = False 85 | 86 | # -- Options for HTML output ---------------------------------------------- 87 | html_theme = "sphinx_rtd_theme" 88 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 89 | # The theme to use for HTML and HTML Help pages. See the documentation for 90 | # a list of builtin themes. 91 | # 92 | # html_theme = 'classic' 93 | 94 | # Theme options are theme-specific and customize the look and feel of a theme 95 | # further. For a list of options available for each theme, see the 96 | # documentation. 97 | # 98 | # html_theme_options = {} 99 | 100 | # Add any paths that contain custom static files (such as style sheets) here, 101 | # relative to this directory. They are copied after the builtin static files, 102 | # so a file named "default.css" will overwrite the builtin "default.css". 103 | # html_static_path = ['_static'] 104 | 105 | # Custom sidebar templates, must be a dictionary that maps document names 106 | # to template names. 107 | # 108 | # This is required for the alabaster theme 109 | # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars 110 | # html_sidebars = { 111 | # '**': [ 112 | # 'about.html', 113 | # 'navigation.html', 114 | # 'relations.html', # needs 'show_related': True theme option to display 115 | # 'searchbox.html', 116 | # 'donate.html', 117 | # ] 118 | # } 119 | 120 | 121 | # -- Options for HTMLHelp output ------------------------------------------ 122 | 123 | # Output file base name for HTML help builder. 124 | htmlhelp_basename = 'PyOpenloaddoc' 125 | 126 | # -- Options for LaTeX output --------------------------------------------- 127 | 128 | latex_elements = { 129 | # The paper size ('letterpaper' or 'a4paper'). 130 | # 131 | # 'papersize': 'letterpaper', 132 | 133 | # The font size ('10pt', '11pt' or '12pt'). 134 | # 135 | # 'pointsize': '10pt', 136 | 137 | # Additional stuff for the LaTeX preamble. 138 | # 139 | # 'preamble': '', 140 | 141 | # Latex figure (float) alignment 142 | # 143 | # 'figure_align': 'htbp', 144 | } 145 | 146 | # Grouping the document tree into LaTeX files. List of tuples 147 | # (source start file, target name, title, 148 | # author, documentclass [howto, manual, or own class]). 149 | latex_documents = [ 150 | (master_doc, 'PyOpenload.tex', 'PyOpenload Documentation', 151 | 'Mohaned Magdy', 'manual'), 152 | ] 153 | 154 | # -- Options for manual page output --------------------------------------- 155 | 156 | # One entry per manual page. List of tuples 157 | # (source start file, name, description, authors, manual section). 158 | man_pages = [ 159 | (master_doc, 'pyopenload', 'PyOpenload Documentation', 160 | [author], 1) 161 | ] 162 | 163 | # -- Options for Texinfo output ------------------------------------------- 164 | 165 | # Grouping the document tree into Texinfo files. List of tuples 166 | # (source start file, target name, title, author, 167 | # dir menu entry, description, category) 168 | texinfo_documents = [ 169 | (master_doc, 'PyOpenload', 'PyOpenload Documentation', 170 | author, 'PyOpenload', 'One line description of project.', 171 | 'Miscellaneous'), 172 | ] 173 | 174 | autodoc_member_order = 'bysource' 175 | -------------------------------------------------------------------------------- /docs/download.rst: -------------------------------------------------------------------------------- 1 | Download 2 | ======== 3 | 4 | Package 5 | ------- 6 | 7 | Source: https://pypi.org/project/pyopenload/ or https://pypi.python.org/pypi/pyopenload/ 8 | 9 | Github: https://github.com/mohan3d/PyOpenload/ 10 | 11 | 12 | Documentation 13 | ------------- 14 | 15 | PDF: https://media.readthedocs.org/pdf/pyopenload/latest/pyopenload.pdf 16 | 17 | HTML: https://media.readthedocs.org/htmlzip/pyopenload/latest/pyopenload.zip -------------------------------------------------------------------------------- /docs/examples.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Examples 3 | ======== 4 | 5 | An instance of OpenLoad is needed for all examples. 6 | 7 | .. literalinclude:: ../examples/base.py 8 | 9 | :samp:`username` and :samp:`key` can be found in `openload user settings `_. 10 | 11 | Account 12 | ======= 13 | 14 | Account Info 15 | ------------ 16 | 17 | Get everything account related (total used storage, reward, ...). 18 | 19 | .. literalinclude:: ../examples/account_infos.py 20 | 21 | 22 | Download 23 | ======== 24 | 25 | Download Ticket 26 | --------------- 27 | 28 | Generate a download token, will be used to generate direct download link. 29 | 30 | .. literalinclude:: ../examples/download_ticket.py 31 | 32 | 33 | Download Link 34 | ------------- 35 | 36 | Generate a download link, after generating a download ticket. 37 | 38 | .. literalinclude:: ../examples/download_link.py 39 | 40 | 41 | Full example 42 | ------------ 43 | 44 | 1) Generate a download token. 45 | 2) Solve captcha if needed. 46 | 3) Generate direct download url. 47 | 48 | .. literalinclude:: ../examples/download_full.py 49 | 50 | 51 | File Info 52 | --------- 53 | 54 | Check the status of a file (id, status, name, size, sha1, content_type). 55 | 56 | .. literalinclude:: ../examples/file_info.py 57 | 58 | 59 | Upload 60 | ====== 61 | 62 | Get an Upload URL 63 | ----------------- 64 | 65 | You may need to use this method only if you want to re-implement :samp:`upload_file` in a different way. 66 | 67 | Generate upload url, will be used to upload a file. 68 | 69 | .. literalinclude:: ../examples/upload_link.py 70 | 71 | 72 | Upload File 73 | ----------- 74 | 75 | .. literalinclude:: ../examples/upload_link.py 76 | 77 | 78 | Remote Upload 79 | ============= 80 | 81 | Add Remote Upload 82 | ----------------- 83 | 84 | Upload latest pyopenload documentation pdf. 85 | 86 | .. literalinclude:: ../examples/remote_upload.py 87 | 88 | 89 | Check Remote Upload Status 90 | -------------------------- 91 | 92 | Check the status of queued remote uploads. 93 | 94 | .. literalinclude:: ../examples/check_remote_upload.py 95 | 96 | 97 | File/Folder Management 98 | ====================== 99 | 100 | List Folder 101 | ----------- 102 | 103 | List :samp:`Home` (The main directory). 104 | 105 | .. literalinclude:: ../examples/list_folder.py 106 | 107 | 108 | Rename Folder 109 | ------------- 110 | 111 | Rename a specific folder. 112 | 113 | .. literalinclude:: ../examples/rename_folder.py 114 | 115 | 116 | Rename File 117 | ----------- 118 | 119 | Rename a specific file. 120 | 121 | .. literalinclude:: ../examples/rename_file.py 122 | 123 | 124 | Delete File 125 | ----------- 126 | 127 | Delete a specific file. 128 | 129 | .. literalinclude:: ../examples/delete_file.py 130 | 131 | 132 | Converting files 133 | ================ 134 | 135 | Convert a file 136 | -------------- 137 | 138 | Convert previously uploaded file to a browser-streamable format :samp:`mp4 / h.264` 139 | 140 | .. literalinclude:: ../examples/convert_file.py 141 | 142 | 143 | Show running file converts 144 | -------------------------- 145 | 146 | List all running conversions. 147 | 148 | .. literalinclude:: ../examples/running_converts.py 149 | 150 | 151 | Show failed file converts 152 | ------------------------- 153 | 154 | Coming soon ... (Not yet implemented by openload.co API). 155 | 156 | 157 | Get splash image 158 | ---------------- 159 | 160 | Get a download url of splash image for a specific uploaded file. 161 | 162 | .. literalinclude:: ../examples/splash_image.py -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. PyOpenload documentation master file, created by 2 | sphinx-quickstart on Wed Aug 9 22:03:50 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PyOpenload's documentation! 7 | ====================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | overview 14 | tutorial 15 | download 16 | install 17 | reference 18 | test 19 | examples 20 | 21 | 22 | Indices and tables 23 | ================== 24 | 25 | * :ref:`genindex` 26 | * :ref:`modindex` 27 | * :ref:`search` 28 | -------------------------------------------------------------------------------- /docs/install.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Installation 3 | ============ 4 | 5 | Quick install 6 | ============= 7 | 8 | Get PyOpenload from the `Python Package Index `_. 9 | 10 | or install it with pip 11 | 12 | .. code-block:: bash 13 | 14 | $ pip install PyOpenload 15 | 16 | You can install the latest version (at github.com). 17 | 18 | .. code-block:: bash 19 | 20 | $ pip install git+https://github.com/mohan3d/PyOpenload 21 | 22 | 23 | Installation from source 24 | ======================== 25 | 26 | Github 27 | ------ 28 | 29 | * Clone the PyOpenload repository 30 | 31 | .. code-block:: bash 32 | 33 | $ git clone https://github.com/mohan3d/PyOpenload.git 34 | 35 | * Change directory to :samp:`PyOpenload` 36 | * Run :samp:`python setup.py install` 37 | 38 | 39 | Requirements 40 | ============ 41 | 42 | Requests 43 | -------- 44 | 45 | `requests `_ is the only required dependency. 46 | -------------------------------------------------------------------------------- /docs/overview.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | PyOpenload is a python wrapper for `Openload.co`_ `API`_. 5 | 6 | |pypi| |format| |CodacyBadge| 7 | 8 | With PyOpenload you can manage your :samp:`openload.co` account (Access account info, Upload files, ...) 9 | with no need to understand how to use `Openload.co`_ `API`_. 10 | 11 | Learn more about what you can do at `Openload.co`_ `API`_. 12 | 13 | 14 | License |license| 15 | ----------------- 16 | 17 | PyOpenload is released under the `MIT License `_, and is fully open-source. 18 | See the actual ``LICENSE`` file distributed with the software for details of the license. 19 | 20 | 21 | About 22 | ----- 23 | 24 | PyOpenload is maintained by: 25 | * `Mohaned Magdy `_ 26 | 27 | .. _Openload.co: https://openload.co 28 | .. _API: https://openload.co/api 29 | 30 | .. |pypi| image:: https://img.shields.io/pypi/v/pyopenload.svg?maxAge=3600&style=flat-square 31 | :target: https://pypi.python.org/pypi/pyopenload 32 | 33 | .. |format| image:: https://img.shields.io/pypi/format/pyopenload.svg?maxAge=3600&style=flat-square 34 | :target: https://pypi.python.org/pypi/pyopenload 35 | 36 | .. |CodacyBadge| image:: https://img.shields.io/codacy/grade/42d0f198fcbe43daae71e21b6a3540fe.svg?maxAge=3600&style=flat-square 37 | :target: https://www.codacy.com/app/mohan3d94/PyOpenload?utm_source=github.com&utm_medium=referral&utm_content=mohan3d/PyOpenload&utm_campaign=badger 38 | 39 | .. |license| image:: https://img.shields.io/pypi/l/pyopenload.svg?maxAge=3600&style=flat-square 40 | :target: https://choosealicense.com/licenses/mit/ -------------------------------------------------------------------------------- /docs/reference.rst: -------------------------------------------------------------------------------- 1 | Reference 2 | ========= 3 | 4 | .. currentmodule:: openload 5 | .. default-role:: any 6 | 7 | .. autoclass:: OpenLoad 8 | :members: 9 | :private-members: 10 | -------------------------------------------------------------------------------- /docs/test.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Testing 3 | ======= 4 | 5 | Requirements 6 | ============ 7 | 8 | ``OPENLOAD_LOGIN`` and ``OPENLOAD_KEY`` must be in your environment variables. 9 | 10 | You may export them in **linux** 11 | 12 | .. code-block:: bash 13 | 14 | export OPENLOAD_LOGIN= 15 | export OPENLOAD_KEY= 16 | 17 | 18 | It is prefered to create new folder in `openload file manager `_ 19 | before starting tests. 20 | 21 | .. note:: You can find OPENLOAD_LOGIN (API Login) and OPENLOAD_KEY (API Key) in openload User Panel at the 22 | `User Settings `_. 23 | 24 | 25 | Testing 26 | ======= 27 | 28 | In the root directory of PyOpenload. 29 | 30 | **Python 3** 31 | 32 | .. code-block:: bash 33 | 34 | $ python -m unittest tests/test_openload.py 35 | 36 | 37 | **Python 2** 38 | 39 | .. code-block:: bash 40 | 41 | $ python -m unittest tests.test_openload -------------------------------------------------------------------------------- /docs/tutorial.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Tutorial 3 | ======== 4 | 5 | Download 6 | ======== 7 | 8 | PyOpenload doesn't download given file id, but gives us direct download url in two steps. 9 | 10 | 1) Generate a download token. 11 | 2) Get direct download url. 12 | 13 | .. code-block:: python 14 | 15 | from __future__ import print_function 16 | 17 | from openload import OpenLoad 18 | 19 | # ----------- OpenLoad instance ----------- 20 | username = 'FTP Username/API Login' 21 | key = 'FTP Password/API Key' 22 | 23 | ol = OpenLoad(username, key) 24 | 25 | # ------------- Generate token ------------ 26 | file_id = 'Id of the file will be downloaded' 27 | 28 | # Get a download ticket and captcha url. 29 | preparation_resp = ol.prepare_download(file_id) 30 | ticket = preparation_resp.get('ticket') 31 | 32 | # Sometimes no captcha is sent in openload.co API response. 33 | captcha_url = preparation_resp.get('captcha_url') 34 | 35 | if captcha_url: 36 | # Solve captcha. 37 | captcha_response = solve_captcha(captcha_url) 38 | else: 39 | captcha_response = '' 40 | 41 | # --------- Get direct download url -------- 42 | download_resp = ol.get_download_link(file_id, ticket, captcha_response) 43 | direct_download_url = download_resp.get('url') 44 | 45 | # Process download url. 46 | download(direct_download_url) 47 | 48 | You must provide implementation of :samp:`solve_captcha` and :samp:`download` functions. 49 | 50 | 51 | Extend 52 | ====== 53 | 54 | Upload large files 55 | ------------------ 56 | 57 | Large files (cannot fit into ram) can be uploaded using :samp:`requests-toolbelt MultipartEncoder`. 58 | 59 | Install :samp:`requests-toolbelt`. 60 | 61 | .. code-block:: bash 62 | 63 | $ pip install requests-toolbelt 64 | 65 | .. code-block:: python 66 | 67 | class MyOpenLoad(OpenLoad): 68 | def upload_large_file(self, file_path, **kwargs): 69 | response = self.upload_link(**kwargs) 70 | upload_url = response['url'] 71 | 72 | _, file_name = os.path.split(file_path) 73 | 74 | with open(file_path, 'rb') as upload_file: 75 | data = encoder.MultipartEncoder({ 76 | "files": (file_name, upload_file, "application/octet-stream"), 77 | }) 78 | 79 | headers = {"Prefer": "respond-async", "Content-Type": data.content_type} 80 | response_json = requests.post(upload_url, headers=headers, data=data).json() 81 | 82 | self._check_status(response_json) 83 | return return response_json['result'] 84 | 85 | 86 | ol = MyOpenLoad('login', 'key') 87 | uploaded_file_info = ol.upload_large_file('FILE_PATH') 88 | 89 | print(uploaded_file_info) 90 | 91 | 92 | .. note:: 93 | 94 | Upload large files code `contributed`_ by `playmusic9`_. 95 | 96 | 97 | .. _contributed: https://github.com/mohan3d/PyOpenload/issues/5#issuecomment-325543121 98 | .. _playmusic9: https://github.com/playmusic9 -------------------------------------------------------------------------------- /examples/account_infos.py: -------------------------------------------------------------------------------- 1 | info = ol.account_info() 2 | 3 | print(info) 4 | -------------------------------------------------------------------------------- /examples/base.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | from openload import OpenLoad 4 | 5 | username = 'FTP Username/API Login' 6 | key = 'FTP Password/API Key' 7 | 8 | ol = OpenLoad(username, key) 9 | -------------------------------------------------------------------------------- /examples/check_remote_upload.py: -------------------------------------------------------------------------------- 1 | resp = ol.remote_upload_status() 2 | 3 | print(resp) 4 | -------------------------------------------------------------------------------- /examples/convert_file.py: -------------------------------------------------------------------------------- 1 | file_id = 'Id of the file(s) to be checked' 2 | 3 | resp = ol.convert_file(file_id) 4 | 5 | print(resp) 6 | -------------------------------------------------------------------------------- /examples/delete_file.py: -------------------------------------------------------------------------------- 1 | file_id = 'Id of the file will be deleted' 2 | 3 | resp = ol.delete_file(file_id) 4 | 5 | print(resp) -------------------------------------------------------------------------------- /examples/download_full.py: -------------------------------------------------------------------------------- 1 | file_id = 'Id of the file will be downloaded' 2 | 3 | # Get a download ticket and captcha url. 4 | preparation_resp = ol.prepare_download(file_id) 5 | ticket = preparation_resp.get('ticket') 6 | 7 | # Sometimes no captcha is sent in openload.co API response. 8 | captcha_url = preparation_resp.get('captcha_url') 9 | 10 | if captcha_url: 11 | # Solve captcha. 12 | captcha_response = solve_captcha(captcha_url) 13 | else: 14 | captcha_response = '' 15 | 16 | download_resp = ol.get_download_link(file_id, ticket, captcha_response) 17 | direct_download_url = download_resp.get('url') 18 | 19 | # Process download url. 20 | print(direct_download_url) 21 | -------------------------------------------------------------------------------- /examples/download_link.py: -------------------------------------------------------------------------------- 1 | file_id = 'Id of the file will be downloaded' 2 | ticket = 'Ticket found in `prepare_download` response' 3 | captcha_response = 'Solution of captcha found in `prepare_download` response' 4 | 5 | resp = ol.get_download_link(file_id, ticket, captcha_response) 6 | direct_download_url = resp.get('url') 7 | 8 | print(direct_download_url) 9 | -------------------------------------------------------------------------------- /examples/download_ticket.py: -------------------------------------------------------------------------------- 1 | file_id = 'Id of the file will be downloaded' 2 | 3 | resp = ol.prepare_download(file_id) 4 | 5 | ticket = resp.get('ticket') 6 | captcha_url = resp.get('captcha_url') 7 | 8 | print(ticket) 9 | print(captcha_url) 10 | -------------------------------------------------------------------------------- /examples/file_info.py: -------------------------------------------------------------------------------- 1 | file_id = 'Id of the file(s) to be checked' 2 | 3 | info = ol.file_info(file_id) 4 | 5 | print(info) 6 | -------------------------------------------------------------------------------- /examples/list_folder.py: -------------------------------------------------------------------------------- 1 | resp = ol.list_folder() 2 | 3 | print(resp) 4 | -------------------------------------------------------------------------------- /examples/remote_upload.py: -------------------------------------------------------------------------------- 1 | pdf_url = 'https://media.readthedocs.org/pdf/pyopenload/latest/pyopenload.pdf' 2 | 3 | resp = ol.remote_upload(pdf_url) 4 | file_id = resp.get('id') 5 | 6 | print(file_id) 7 | -------------------------------------------------------------------------------- /examples/rename_file.py: -------------------------------------------------------------------------------- 1 | file_id = 'Id of the file will be renamed' 2 | 3 | resp = ol.rename_file(file_id, '') 4 | 5 | print(resp) 6 | -------------------------------------------------------------------------------- /examples/rename_folder.py: -------------------------------------------------------------------------------- 1 | folder_id = 'Id of the folder will be renamed' 2 | 3 | resp = ol.rename_folder(folder_id, '') 4 | 5 | print(resp) 6 | -------------------------------------------------------------------------------- /examples/running_converts.py: -------------------------------------------------------------------------------- 1 | resp = ol.running_conversions() 2 | 3 | print(resp) 4 | -------------------------------------------------------------------------------- /examples/splash_image.py: -------------------------------------------------------------------------------- 1 | file_id = 'Id of the file will be downloaded' 2 | 3 | resp = ol.splash_image(file_id) 4 | 5 | print(resp) 6 | -------------------------------------------------------------------------------- /examples/upload_file.py: -------------------------------------------------------------------------------- 1 | file_path = '/home/username/file.txt' 2 | 3 | resp = ol.upload_file(file_path) 4 | uploaded_url = resp.get('url') 5 | 6 | print(uploaded_url) 7 | -------------------------------------------------------------------------------- /examples/upload_link.py: -------------------------------------------------------------------------------- 1 | resp = ol.upload_link() 2 | upload_link = resp.get('url') 3 | 4 | print(upload_link) 5 | -------------------------------------------------------------------------------- /openload/__init__.py: -------------------------------------------------------------------------------- 1 | from .openload import OpenLoad 2 | -------------------------------------------------------------------------------- /openload/api_exceptions.py: -------------------------------------------------------------------------------- 1 | class BadRequestException(Exception): 2 | pass 3 | 4 | 5 | class PermissionDeniedException(Exception): 6 | pass 7 | 8 | 9 | class FileNotFoundException(Exception): 10 | pass 11 | 12 | 13 | class TooManyRequestsException(Exception): 14 | pass 15 | 16 | 17 | class UnavailableForLegalReasonsException(Exception): 18 | pass 19 | 20 | 21 | class BandwidthUsageExceeded(Exception): 22 | pass 23 | 24 | 25 | class ServerErrorException(Exception): 26 | pass 27 | -------------------------------------------------------------------------------- /openload/openload.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import os 4 | 5 | import requests 6 | import requests_toolbelt 7 | 8 | from .api_exceptions import (BadRequestException, BandwidthUsageExceeded, FileNotFoundException, 9 | PermissionDeniedException, TooManyRequestsException, ServerErrorException, 10 | UnavailableForLegalReasonsException) 11 | 12 | 13 | class OpenLoad(object): 14 | api_base_url = 'https://api.openload.co/{api_version}/' 15 | api_version = '1' 16 | 17 | def __init__(self, api_login, api_key): 18 | """Initializes OpenLoad instance with given parameters and formats api base url. 19 | 20 | Args: 21 | api_login (str): API Login found in openload.co 22 | api_key (str): API Key found in openload.co 23 | 24 | Returns: 25 | None 26 | 27 | """ 28 | self.login = api_login 29 | self.key = api_key 30 | self.api_url = self.api_base_url.format(api_version=self.api_version) 31 | 32 | @classmethod 33 | def _check_status(cls, response_json): 34 | """Check the status of the incoming response, raise exception if status is not 200. 35 | 36 | Args: 37 | response_json (dict): results of the response of the GET request. 38 | 39 | Returns: 40 | None 41 | 42 | """ 43 | status = response_json['status'] 44 | msg = response_json['msg'] 45 | 46 | if status == 400: 47 | raise BadRequestException(msg) 48 | elif status == 403: 49 | raise PermissionDeniedException(msg) 50 | elif status == 404: 51 | raise FileNotFoundException(msg) 52 | elif status == 429: 53 | raise TooManyRequestsException(msg) 54 | elif status == 451: 55 | raise UnavailableForLegalReasonsException(msg) 56 | elif status == 509: 57 | raise BandwidthUsageExceeded(msg) 58 | elif status >= 500: 59 | raise ServerErrorException(msg) 60 | 61 | @classmethod 62 | def _process_response(cls, response_json): 63 | """Check the incoming response, raise error if it's needed otherwise return the incoming response_json 64 | 65 | Args: 66 | response_json (dict): results of the response of the GET request. 67 | 68 | Returns: 69 | dict: results of the response of the GET request. 70 | 71 | """ 72 | 73 | cls._check_status(response_json) 74 | return response_json['result'] 75 | 76 | def _get(self, url, params=None): 77 | """Used by every other method, it makes a GET request with the given params. 78 | 79 | Args: 80 | url (str): relative path of a specific service (account_info, ...). 81 | params (:obj:`dict`, optional): contains parameters to be sent in the GET request. 82 | 83 | Returns: 84 | dict: results of the response of the GET request. 85 | 86 | """ 87 | if not params: 88 | params = {} 89 | 90 | params.update({'login': self.login, 'key': self.key}) 91 | 92 | response_json = requests.get(self.api_url + url, params).json() 93 | 94 | return self._process_response(response_json) 95 | 96 | def account_info(self): 97 | """Requests everything account related (total used storage, reward, ...). 98 | 99 | Returns: 100 | dict: dictionary containing account related info. :: 101 | 102 | { 103 | "extid": "extuserid", 104 | "email": "jeff@openload.io", 105 | "signup_at": "2015-01-09 23:59:54", 106 | "storage_left": -1, 107 | "storage_used": "32922117680", 108 | "traffic": { 109 | "left": -1, 110 | "used_24h": 0 111 | }, 112 | "balance": 0 113 | } 114 | 115 | """ 116 | return self._get('account/info') 117 | 118 | def prepare_download(self, file_id): 119 | """Makes a request to prepare for file download, 120 | this download preparation will be used before get_download_link method. 121 | 122 | Args: 123 | file_id (str): id of the file to be downloaded. 124 | 125 | Returns: 126 | dict: dictionary containing (ticket, captcha info, ...). :: 127 | 128 | { 129 | "ticket": "72fA-_Lq8Ak~~1440353112~n~~0~nXtN3RI-nsEa28Iq", 130 | "captcha_url": "https://openload.co/dlcaptcha/b92eY_nfjV4.png", 131 | "captcha_w": 140, 132 | "captcha_h": 70, 133 | "wait_time": 10, 134 | "valid_until": "2015-08-23 18:20:13" 135 | } 136 | 137 | """ 138 | return self._get('file/dlticket', params={'file': file_id}) 139 | 140 | def get_download_link(self, file_id, ticket, captcha_response=None): 141 | """Requests direct download link for requested file, 142 | this method makes use of the response of prepare_download, prepare_download must be called first. 143 | 144 | Args: 145 | file_id (str): id of the file to be downloaded. 146 | 147 | ticket (str): preparation ticket is found in prepare_download response,\ 148 | this is why we need to call prepare_download before get_download_link. 149 | 150 | captcha_response (:obj:`str`, optional): sometimes prepare_download will have captcha url to be solved, \ 151 | first, this is the solution of the captcha. 152 | 153 | Returns: 154 | dict: dictionary containing (file info, download url, ...). :: 155 | 156 | { 157 | "name": "The quick brown fox.txt", 158 | "size": 12345, 159 | "sha1": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", 160 | "content_type": "plain/text", 161 | "upload_at": "2011-01-26 13:33:37", 162 | "url": "https://abvzps.example.com/dl/l/4spxX_-cSO4/The+quick+brown+fox.txt", 163 | "token": "4spxX_-cSO4" 164 | } 165 | 166 | """ 167 | params = {'ticket': ticket, 'file': file_id} 168 | 169 | if captcha_response: 170 | params['captcha_response'] = captcha_response 171 | 172 | return self._get('file/dl', params) 173 | 174 | def file_info(self, file_id): 175 | """Used to request info for a specific file, info like size, name, ..... 176 | 177 | Args: 178 | file_id (str): File-ID(s), single file or comma-separated (max. 50) 179 | 180 | Returns: 181 | dict: dictionary containing file(s) info, each key represents a file_id. :: 182 | 183 | { 184 | "72fA-_Lq8Ak3": { 185 | "id": "72fA-_Lq8Ak3", 186 | "status": 200, 187 | "name": "The quick brown fox.txt", 188 | "size": 123456789012, 189 | "sha1": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", 190 | "content_type": "plain/text", 191 | }, 192 | "72fA-_Lq8Ak4": { 193 | "id": "72fA-_Lq8Ak4", 194 | "status": 500, 195 | "name": "The quick brown fox.txt", 196 | "size": false, 197 | "sha1": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", 198 | "content_type": "plain/text", 199 | }, 200 | ... 201 | } 202 | 203 | """ 204 | return self._get('file/info', params={'file': file_id}) 205 | 206 | def upload_link(self, folder_id=None, sha1=None, httponly=False): 207 | """Makes a request to prepare for file upload. 208 | 209 | Note: 210 | If folder_id is not provided, it will make and upload link to the ``Home`` folder. 211 | 212 | Args: 213 | folder_id (:obj:`str`, optional): folder-ID to upload to. 214 | sha1 (:obj:`str`, optional): expected sha1 If sha1 of uploaded file doesn't match this value, upload fails. 215 | httponly (:obj:`bool`, optional): If this is set to true, use only http upload links. 216 | 217 | Returns: 218 | dict: dictionary containing (url: will be used in actual upload, valid_until). :: 219 | 220 | { 221 | "url": "https://1fiafqj.oloadcdn.net/uls/nZ8H3X9e0AotInbU", 222 | "valid_until": "2017-08-19 19:06:46" 223 | } 224 | 225 | """ 226 | 227 | kwargs = {'folder': folder_id, 'sha1': sha1, 'httponly': httponly} 228 | params = {key: value for key, value in kwargs.items() if value} 229 | return self._get('file/ul', params=params) 230 | 231 | def upload_file(self, file_path, folder_id=None, sha1=None, httponly=False): 232 | """Calls upload_link request to get valid url, then it makes a post request with given file to be uploaded. 233 | No need to call upload_link explicitly since upload_file calls it. 234 | 235 | Note: 236 | If folder_id is not provided, the file will be uploaded to ``Home`` folder. 237 | 238 | Args: 239 | file_path (str): full path of the file to be uploaded. 240 | folder_id (:obj:`str`, optional): folder-ID to upload to. 241 | sha1 (:obj:`str`, optional): expected sha1 If sha1 of uploaded file doesn't match this value, upload fails. 242 | httponly (:obj:`bool`, optional): If this is set to true, use only http upload links. 243 | 244 | Returns: 245 | dict: dictionary containing uploaded file info. :: 246 | 247 | { 248 | "content_type": "application/zip", 249 | "id": "0yiQTPzi4Y4", 250 | "name": 'favicons.zip', 251 | "sha1": 'f2cb05663563ec1b7e75dbcd5b96d523cb78d80c', 252 | "size": '24160', 253 | "url": 'https://openload.co/f/0yiQTPzi4Y4/favicons.zip' 254 | } 255 | 256 | """ 257 | 258 | upload_url_response_json = self.upload_link(folder_id=folder_id, sha1=sha1, httponly=httponly) 259 | upload_url = upload_url_response_json['url'] 260 | 261 | _, file_name = os.path.split(file_path) 262 | 263 | with open(file_path, 'rb') as f: 264 | data = requests_toolbelt.MultipartEncoder({ 265 | "files": (file_name, f, "application/octet-stream"), 266 | }) 267 | 268 | headers = {"Content-Type": data.content_type} 269 | response_json = requests.post(upload_url, data=data, headers=headers).json() 270 | 271 | self._check_status(response_json) 272 | return response_json['result'] 273 | 274 | def remote_upload(self, remote_url, folder_id=None, headers=None): 275 | """Used to make a remote file upload to openload.co 276 | 277 | Note: 278 | If folder_id is not provided, the file will be uploaded to ``Home`` folder. 279 | 280 | Args: 281 | remote_url (str): direct link of file to be remotely downloaded. 282 | folder_id (:obj:`str`, optional): folder-ID to upload to. 283 | headers (:obj:`dict`, optional): additional HTTP headers (e.g. Cookies or HTTP Basic-Auth) 284 | 285 | Returns: 286 | dict: dictionary containing ("id": uploaded file id, "folderid"). :: 287 | 288 | { 289 | "id": "12", 290 | "folderid": "4248" 291 | } 292 | 293 | """ 294 | 295 | kwargs = {'folder': folder_id, 'headers': headers} 296 | params = {'url': remote_url} 297 | params.update({key: value for key, value in kwargs.items() if value}) 298 | 299 | return self._get('remotedl/add', params=params) 300 | 301 | def remote_upload_status(self, limit=None, remote_upload_id=None): 302 | """Checks a remote file upload to status. 303 | 304 | Args: 305 | limit (:obj:`int`, optional): Maximum number of results (Default: 5, Maximum: 100). 306 | remote_upload_id (:obj:`str`, optional): Remote Upload ID. 307 | 308 | Returns: 309 | dict: dictionary containing all remote uploads, each dictionary element is a dictionary. :: 310 | 311 | { 312 | "24": { 313 | "id": "24", 314 | "remoteurl": "http://proof.ovh.net/files/100Mio.dat", 315 | "status": "new", 316 | "folderid": "4248", 317 | "added": "2015-02-21 09:20:26", 318 | "last_update": "2015-02-21 09:20:26", 319 | "extid": False, 320 | "url": False 321 | }, 322 | "22": { 323 | "id": "22", 324 | "remoteurl": "http://proof.ovh.net/files/1Gio.dat", 325 | "status": "downloading", 326 | "bytes_loaded": "823997062", 327 | "bytes_total": "1073741824", 328 | "folderid": "4248", 329 | "added": "2015-02-21 09:20:26", 330 | "last_update": "2015-02-21 09:21:56", 331 | "extid": False, 332 | "url": False 333 | }, 334 | ... 335 | } 336 | 337 | """ 338 | 339 | kwargs = {'limit': limit, 'id': remote_upload_id} 340 | params = {key: value for key, value in kwargs.items() if value} 341 | 342 | return self._get('remotedl/status', params=params) 343 | 344 | def list_folder(self, folder_id=None): 345 | """Request a list of files and folders in specified folder. 346 | 347 | Note: 348 | if folder_id is not provided, ``Home`` folder will be listed 349 | 350 | Args: 351 | folder_id (:obj:`str`, optional): id of the folder to be listed. 352 | 353 | Returns: 354 | dict: dictionary containing only two keys ("folders", "files"), \ 355 | each key represents a list of dictionaries. :: 356 | 357 | { 358 | "folders": [ 359 | { 360 | "id": "5144", 361 | "name": ".videothumb" 362 | }, 363 | { 364 | "id": "5792", 365 | "name": ".subtitles" 366 | }, 367 | ... 368 | ], 369 | "files": [ 370 | { 371 | "name": "big_buck_bunny.mp4.mp4", 372 | "sha1": "c6531f5ce9669d6547023d92aea4805b7c45d133", 373 | "folderid": "4258", 374 | "upload_at": "1419791256", 375 | "status": "active", 376 | "size": "5114011", 377 | "content_type": "video/mp4", 378 | "download_count": "48", 379 | "cstatus": "ok", 380 | "link": "https://openload.co/f/UPPjeAk--30/big_buck_bunny.mp4.mp4", 381 | "linkextid": "UPPjeAk--30" 382 | }, 383 | ... 384 | ] 385 | } 386 | 387 | """ 388 | params = {'folder': folder_id} if folder_id else {} 389 | 390 | return self._get('file/listfolder', params=params) 391 | 392 | def rename_folder(self, folder_id, name): 393 | """Sets a new name for a folders 394 | 395 | Note: 396 | folder_id(s) can be found in list_folder return. 397 | 398 | Args: 399 | folder_id (str): id of the folder to be renamed. 400 | name (str): new name for the provided folder. 401 | 402 | Returns: 403 | bool: True if folder is renamed, otherwise False. 404 | 405 | """ 406 | return self._get('file/renamefolder', params={'folder': folder_id, 'name': name}) 407 | 408 | def rename_file(self, file_id, name): 409 | """Sets a new name for a file 410 | 411 | Args: 412 | file_id (str): id of the file to be renamed. 413 | name (str): new name for the provided file. 414 | 415 | Returns: 416 | bool: True if file is renamed, otherwise False. 417 | 418 | """ 419 | return self._get('file/rename', params={'file': file_id, 'name': name}) 420 | 421 | def delete_file(self, file_id): 422 | """Removes one of your files 423 | 424 | Args: 425 | file_id (str): id of the file to be deleted. 426 | 427 | Returns: 428 | bool: True if file is deleted, otherwise False. 429 | 430 | """ 431 | return self._get('file/delete', params={'file': file_id}) 432 | 433 | def convert_file(self, file_id): 434 | """Converts previously uploaded files to a browser-streamable format (mp4 / h.264). 435 | 436 | Args: 437 | file_id (str): id of the file to be converted. 438 | 439 | Returns: 440 | bool: True if conversion started, otherwise False. 441 | 442 | """ 443 | return self._get('file/convert', params={'file': file_id}) 444 | 445 | def running_conversions(self, folder_id=None): 446 | """Shows running file converts by folder 447 | 448 | Note: 449 | If folder_id is not provided, ``Home`` folder will be used. 450 | 451 | Args: 452 | folder_id (:obj:`str`, optional): id of the folder to list conversions of files exist in it. 453 | 454 | Returns: 455 | list: list of dictionaries, each dictionary represents a file conversion info. :: 456 | 457 | [ 458 | { 459 | "name": "Geysir.AVI", 460 | "id": "3565411", 461 | "status": "pending", 462 | "last_update": "2015-08-23 19:41:40", 463 | "progress": 0.32, 464 | "retries": "0", 465 | "link": "https://openload.co/f/f02JFG293J8/Geysir.AVI", 466 | "linkextid": "f02JFG293J8" 467 | }, 468 | .... 469 | ] 470 | 471 | """ 472 | params = {'folder': folder_id} if folder_id else {} 473 | return self._get('file/runningconverts', params=params) 474 | 475 | def failed_conversions(self): 476 | """ 477 | Not yet implemented, openload.co said "Coming soon ...". 478 | 479 | Raises: 480 | NotImplementedError 481 | 482 | """ 483 | raise NotImplementedError 484 | 485 | def splash_image(self, file_id): 486 | """Shows the video splash image (thumbnail) 487 | 488 | Args: 489 | file_id (str): id of the target file. 490 | 491 | Returns: 492 | str: url for the splash image. 493 | 494 | """ 495 | return self._get('file/getsplash', params={'file': file_id}) 496 | -------------------------------------------------------------------------------- /requirements-doc.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | sphinx-rtd-theme -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal=1 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from codecs import open as copen 2 | from os import path 3 | 4 | from setuptools import setup, find_packages 5 | 6 | here = path.abspath(path.dirname(__file__)) 7 | 8 | with copen(path.join(here, 'README.rst'), encoding='utf-8') as f: 9 | long_description = f.read() 10 | 11 | setup( 12 | name='pyopenload', 13 | version='0.7', 14 | description='Python wrapper for openload.co API', 15 | long_description=long_description, 16 | url='https://github.com/mohan3d/PyOpenload', 17 | author='Mohaned Magdy', 18 | author_email='mohan3d94@gmail.com', 19 | license='MIT', 20 | classifiers=[ 21 | 'Development Status :: 4 - Beta', 22 | 'Intended Audience :: Developers', 23 | 'Topic :: Internet :: WWW/HTTP', 24 | 'License :: OSI Approved :: MIT License', 25 | 'Programming Language :: Python :: 2', 26 | 'Programming Language :: Python :: 2.7', 27 | 'Programming Language :: Python :: 3', 28 | 'Programming Language :: Python :: 3.3', 29 | 'Programming Language :: Python :: 3.4', 30 | 'Programming Language :: Python :: 3.5', 31 | 'Programming Language :: Python :: 3.6', 32 | 'Programming Language :: Python :: 3.7', 33 | ], 34 | keywords=['openload', 'wrapper', 'api', 'api client'], 35 | packages=find_packages(exclude=['docs', 'tests*']), 36 | install_requires=['requests>=2.20.0', 'requests-toolbelt==0.9.1'], 37 | ) 38 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.insert(0, os.path.abspath('..')) 4 | -------------------------------------------------------------------------------- /tests/file.txt: -------------------------------------------------------------------------------- 1 | Just empty file. -------------------------------------------------------------------------------- /tests/test_openload.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | import openload 5 | 6 | 7 | class TestOpenLoad(unittest.TestCase): 8 | def setUp(self): 9 | login = os.environ.get('OPENLOAD_LOGIN') 10 | key = os.environ.get('OPENLOAD_KEY') 11 | 12 | self.ol = openload.OpenLoad(login, key) 13 | 14 | self.file_path = os.path.join( 15 | os.path.abspath(os.path.dirname(__file__)), 'file.txt') 16 | 17 | self.uploaded_files_ids = [] 18 | 19 | def tearDown(self): 20 | file_ids = self.uploaded_files_ids 21 | 22 | if file_ids: 23 | self.delete_test_files(file_ids) 24 | 25 | def delete_test_files(self, ids): 26 | for file_id in ids: 27 | self.ol.delete_file(file_id) 28 | 29 | def get_folder_id(self): 30 | home_folder_info = self.ol.list_folder() 31 | folders = home_folder_info.get('folders') 32 | 33 | if folders: 34 | return folders[-1].get('id') 35 | 36 | def test_account_info(self): 37 | account_info = self.ol.account_info() 38 | keys = ['balance', 'email', 'extid', 'signup_at', 'storage_left', 'storage_used', 'traffic'] 39 | 40 | self.assertIsInstance(account_info, dict) 41 | 42 | for key in keys: 43 | self.assertIn(key, account_info) 44 | 45 | def test_upload_link(self): 46 | upload_link_info = self.ol.upload_link() 47 | 48 | self.assertIsInstance(upload_link_info, dict) 49 | self.assertIn('url', upload_link_info) 50 | self.assertIn('valid_until', upload_link_info) 51 | 52 | def test_upload_file_without_folder(self): 53 | file_info = self.ol.upload_file(self.file_path) 54 | keys = ['content_type', 'id', 'name', 'sha1', 'size', 'url'] 55 | 56 | self.uploaded_files_ids.append(file_info.get('id')) 57 | 58 | self.assertIsInstance(file_info, dict) 59 | 60 | for key in keys: 61 | self.assertIn(key, file_info) 62 | 63 | def test_upload_file_with_folder(self): 64 | folder_id = self.get_folder_id() 65 | file_info = self.ol.upload_file(self.file_path, folder_id=folder_id) 66 | file_id = file_info.get('id') 67 | 68 | self.uploaded_files_ids.append(file_id) 69 | 70 | folder_info = self.ol.list_folder(folder_id) 71 | file_ids = [f.get('linkextid') for f in folder_info.get('files')] 72 | 73 | self.assertIn(file_id, file_ids) 74 | 75 | def test_file_info_single_file(self): 76 | uploaded_file_info = self.ol.upload_file(self.file_path) 77 | file_id = uploaded_file_info.get('id') 78 | 79 | self.uploaded_files_ids.append(file_id) 80 | 81 | file_info = self.ol.file_info(file_id) 82 | 83 | self.assertIsInstance(file_info, dict) 84 | self.assertIn(file_id, file_info) 85 | self.assertIsInstance(file_info.get(file_id), dict) 86 | 87 | def test_file_info_multiple_files(self): 88 | uploaded_files_info = [self.ol.upload_file(self.file_path), 89 | self.ol.upload_file(self.file_path), 90 | self.ol.upload_file(self.file_path)] 91 | 92 | files_ids = [info.get('id') for info in uploaded_files_info] 93 | self.uploaded_files_ids.extend([file_id for file_id in files_ids if file_id]) 94 | 95 | self.assertTrue(all(files_ids)) 96 | 97 | files_info = self.ol.file_info(','.join(files_ids)) 98 | 99 | for file_id, file_info in files_info.items(): 100 | self.assertIsInstance(file_info, dict) 101 | self.assertIn(file_id, files_info) 102 | self.assertIsInstance(files_info.get(file_id), dict) 103 | 104 | def test_prepare_download(self): 105 | file_info = self.ol.upload_file(self.file_path) 106 | file_id = file_info.get('id') 107 | keys = ["ticket", "captcha_url", "captcha_w", "captcha_h", "wait_time", "valid_until"] 108 | 109 | self.uploaded_files_ids.append(file_id) 110 | 111 | prepare_info = self.ol.prepare_download(file_id) 112 | 113 | self.assertIsInstance(prepare_info, dict) 114 | 115 | for key in keys: 116 | self.assertIn(key, prepare_info) 117 | 118 | def test_list_folder(self): 119 | folder_id = self.get_folder_id() 120 | folder_info = self.ol.list_folder(folder_id) 121 | 122 | self.assertIsInstance(folder_info, dict) 123 | self.assertIn('folders', folder_info) 124 | self.assertIn('files', folder_info) 125 | 126 | def test_rename_file(self): 127 | file_info = self.ol.upload_file(self.file_path) 128 | file_id = file_info.get('id') 129 | self.uploaded_files_ids.append(file_id) 130 | 131 | succeeded = self.ol.rename_file(file_id, 'NEW_NAME') 132 | self.assertTrue(succeeded) 133 | 134 | def test_delete_file(self): 135 | file_info = self.ol.upload_file(self.file_path) 136 | file_id = file_info.get('id') 137 | 138 | succeeded = self.ol.delete_file(file_id) 139 | self.assertTrue(succeeded) 140 | 141 | def test_running_conversions_without_folder(self): 142 | conversions = self.ol.running_conversions() 143 | self.assertIsInstance(conversions, list) 144 | 145 | def test_running_conversions_with_folder(self): 146 | folder_id = self.get_folder_id() 147 | conversions = self.ol.running_conversions(folder_id=folder_id) 148 | self.assertIsInstance(conversions, list) 149 | 150 | def test_remote_upload_status(self): 151 | remote_upload_status_info = self.ol.remote_upload_status() 152 | if remote_upload_status_info: 153 | self.assertIsInstance(remote_upload_status_info, dict) 154 | 155 | 156 | if __name__ == '__main__': 157 | unittest.main() 158 | --------------------------------------------------------------------------------