[
  {
    "path": ".all-contributorsrc",
    "content": "{\n  \"files\": [\n    \"README.md\"\n  ],\n  \"imageSize\": 100,\n  \"commit\": false,\n  \"contributors\": [\n    {\n      \"login\": \"Gupta-Anubhav12\",\n      \"name\": \"Anubhav Gupta\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/64721638?v=4\",\n      \"profile\": \"https://github.com/Gupta-Anubhav12\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"sanujsood\",\n      \"name\": \"Sanuj Sood\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/67072668?v=4\",\n      \"profile\": \"https://github.com/sanujsood\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"aahnik\",\n      \"name\": \"Aahnik Daw\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/66209958?v=4\",\n      \"profile\": \"http://aahnik.dev\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"akshatj2209\",\n      \"name\": \"Akshat Joshi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/57488922?v=4\",\n      \"profile\": \"https://github.com/akshatj2209\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Amritpal2001\",\n      \"name\": \"Amritpal Singh\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/60562606?v=4\",\n      \"profile\": \"https://www.realdevils.com/\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"NIKU-SINGH\",\n      \"name\": \"Niku Singh\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/72123526?v=4\",\n      \"profile\": \"https://github.com/NIKU-SINGH\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"sreevardhanreddi\",\n      \"name\": \"sreevardhanreddi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/31174432?v=4\",\n      \"profile\": \"https://sreevardhanreddi.github.io/\",\n      \"contributions\": [\n        \"code\",\n        \"infra\"\n      ]\n    }\n  ],\n  \"contributorsPerLine\": 7,\n  \"projectName\": \"bhagavad-gita-api\",\n  \"projectOwner\": \"gita\",\n  \"repoType\": \"github\",\n  \"repoHost\": \"https://github.com\",\n  \"skipCi\": true\n}\n"
  },
  {
    "path": ".dockerignore",
    "content": "# Custom ignore\n.vscode\nt.*\ntest.py\nfoo.py\nrun.py\n\n# Standard python .dockerignore used by community\n\n# Git\n.git\n.gitignore\n\n# CI\n.codeclimate.yml\n.travis.yml\n.taskcluster.yml\n\n# Docker\ndocker-compose.yml\n.docker\n\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*/__pycache__/\n*/*/__pycache__/\n*/*/*/__pycache__/\n*.py[cod]\n*/*.py[cod]\n*/*/*.py[cod]\n*/*/*/*.py[cod]\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.cache\nnosetests.xml\ncoverage.xml\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Virtual environment\n.env/\n.venv/\nvenv/\n\n# PyCharm\n.idea\n\n# Python mode for VIM\n.ropeproject\n*/.ropeproject\n*/*/.ropeproject\n*/*/*/.ropeproject\n\n# Vim swap files\n*.swp\n*/*.swp\n*/*/*.swp\n*/*/*/*.swp\n\n# volume folder for postgres database\ndb_data\n"
  },
  {
    "path": ".flake8",
    "content": "[flake8]\nmax-line-length = 88\nselect = C,E,F,W,B,B9\nignore = E203, E501, W503, E712, E301, F403, F405\nexclude = .tox,.git,venv,__init__.py\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing Guide\n\nThis guide is for anyone who wishes to contribute code to Bhagavad Gita API.\n\nThank you for your interest and welcome here!\n\nTo work on this project you will need the following software installed in your machine.\n\n- git (version control)\n- python3.10 or above\n- poetry (package management)\n- make (command line utils)\n- docker (optional, if you want to build docker images)\n- docker-compose (optional, if you want to develop with docker-compose)\n\n1. First of all fork and clone this repo. Checkout a new branch to start working.\nFor more information read\n[GitHub's Docs](https://docs.github.com/en/get-started/quickstart/fork-a-repo)\nfor beginners.\n\n2. If you don't already have `poetry`, then [install it](https://python-poetry.org/docs/#installation).\nMove into the project directory and run the following commands.\n\n    ```shell\n    poetry config virtualenvs.in-project true\n    poetry install\n    ```\n\n3. The virtual environment will be created in a `.venv` folder inside your\nproject directory.\nIn your code editor set the python interpretor path to `./.venv/bin/python`\n\n4. Activate poetry shell.\n\n    ```shell\n    poetry shell\n    ```\n\n5. Install pre-commit hooks.\n\n    ```shell\n    pre-commit install\n    ```\n\n6. Setup .env file refer .env.example.\n\n    ```shell\n    cp .env.example .env\n    ```\n\n7. Seed data to database.\n\n    ```shell\n    python bhagavad_gita_api/cli.py seed-data\n    ```\n\n8. To start the server with hot reload,\n\n    ```shell\n    uvicorn bhagavad_gita_api.main:app --host 0.0.0.0 --port 8081 --reload\n    ```\n\n    By default an in memory Sqlite database is used.\n    To set the database DSN, tester API Key and other stuff, read about\n    [configuration](../README.md/#Configuration) in the README.\n\n9. Try to write test cases when you are adding a feature or fixing a bug.\n\n10. Make sure that all existing tests, and code quality checks pass.\n\n    ```shell\n    pytest # run tests\n    pre-commit run -a # run pre-commit for all files\n    ```\n\n11. Make sure to write meaningful commit messages.\n\n12. Open a PR. Please explain what your changes does in a simple words.\nAttach logs, screenshots and other relevant material.\n\nCongrats and thanks for opening your first PR!\nPlease wait for the maintainers to respond.\n\n---\n\n## Developing with Docker and docker-compose\n\n```shell\n\n# setup .env file, refer .env.example file\ncp .env.example .env\n\n# run the project with docker-compose\ndocker-compose -f docker-compose.dev.yml up --build\n\n```\n\n---\n\n## Contributors List\n\nTo add yourself to the contributors list, comment on an Issue or Pull Request,\nasking @all-contributors to add a contributor:\n\n```txt\n@all-contributors please add @<username> for <contributions>\n```\n\n**\\<contribution>**: See the [Emoji Key (Contribution Types Reference)](../emoji-key)\n for a list of valid `contribution` types.\n\nThe bot will then create a Pull Request to add the contributor,\nthen reply with the pull request details.\n\n![Example usage screenshot](../.github/bot-usage.png \"Example usage\")\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: gita\npatreon: # Replace with a single Patreon username\nopen_collective: the-gita-initiative\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: gita\notechie: # Replace with a single Otechie username\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug.yml",
    "content": "name: Bug report\ndescription: Create a report to help us improve. Report bugs found while using the project\ntitle: \"[BUG] <description>\"\nlabels: [\"🛠 goal: fix\"]\nbody:\n  - type: textarea\n    id: actualbhv\n    attributes:\n      label: \"🙁 Actual behavior\"\n      description: What happened, and why it was wrong\n    validations:\n      required: true\n  - type: textarea\n    id: expectedbhv\n    attributes:\n      label: \"🙂 Expected behavior\"\n      description: What you expected to happen instead, and why\n    validations:\n      required: true\n  - type: textarea\n    id: steps\n    attributes:\n      label: \"🔢 Steps to Reproduce the Problem\"\n      description: If possible, provide steps to reproduce the problem you're experiencing\n      placeholder: |\n        1. First step\n        2. Second step\n        3. Third step\n    validations:\n      required: false\n  - type: markdown\n    attributes:\n      value: |\n        You can also join the Discord community [here](https://discord.gg/HPZzuJs3VY)\n        Feel free to check out other cool repositories of the The Gita Initiative Communtiy [here](https://github.com/gita)\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature.yml",
    "content": "name: Feature request\ndescription: Suggest features, propose improvements, discuss new ideas\ntitle: \"[FEATURE] <description>\"\nlabels: [\"⭐ goal: addition\"]\nbody:\n  - type: textarea\n    id: suggestion\n    attributes:\n      label: ⭐ Suggestion\n      description: A summary of what you'd like to see added or changed\n    validations:\n      required: true\n  - type: textarea\n    id: usecases\n    attributes:\n      label: 💻 Use Cases\n      description: |\n        What are possible you cases for your suggested feature?\n        Are you using any workarounds in the meantime?\n    validations:\n      required: false\n  - type: textarea\n    id: relatedproblems\n    attributes:\n      label: ❌ Related Problems\n      description: |\n        Is your Request related to a problem?\n        Think about linking existing Issues here!\n    validations:\n      required: false\n  - type: markdown\n    attributes:\n      value: |\n        You can also join the Discord community [here](https://discord.gg/HPZzuJs3VY)\n        Feel free to check out other cool repositories of the The Gita Initiative Communtiy [here](https://github.com/gita)\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/other.yml",
    "content": "name: Other\ndescription: Use this for any other issues. PLEASE do not create blank issues\ntitle: \"[OTHER]\"\nlabels: [\"🚦 status: awaiting triage\"]\nbody:\n  - type: markdown\n    attributes:\n      value: \"# Other issue\"\n  - type: textarea\n    id: issuedescription\n    attributes:\n      label: What would you like to share?\n      description: Provide a clear and concise explanation of your issue.\n    validations:\n      required: true\n  - type: textarea\n    id: extrainfo\n    attributes:\n      label: Additional information\n      description: Is there anything else we should know about this issue?\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/pull_request_template.md",
    "content": "# Description\n\nPlease include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.\n\nFixes # (issue)\n\n## Type of change\n\nPlease delete options that are not relevant.\n\n- [ ] Bug fix (non-breaking change which fixes an issue)\n- [ ] New feature (non-breaking change which adds functionality)\n- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)\n- [ ] This change requires a documentation update\n\n\n# Checklist:\n\n- [ ] My code follows the style guidelines of this project\n- [ ] I have performed a self-review of my own code\n- [ ] I have commented my code, particularly in hard-to-understand areas\n- [ ] I have made corresponding changes to the documentation\n- [ ] My changes generate no new warnings\n- [ ] I have added tests that prove my fix is effective or that my feature works\n- [ ] New and existing unit tests pass locally with my changes\n- [ ] Any dependent changes have been merged and published in downstream modules\n"
  },
  {
    "path": ".github/workflows/deploy.yml",
    "content": "name: Deploy to VM\n\non:\n  push:\n    branches: [main]\n\njobs:\n  deploy:\n    runs-on: [self-hosted]\n    steps:\n      - name: cleanup and reset permissions to user from docker user\n        run: chown -R $USER:$USER $GITHUB_WORKSPACE\n\n      - name: download source code\n        uses: actions/checkout@v2\n\n      - name: set environment variables in .env file\n        run: |\n          echo POSTGRES_USER=\"${{ secrets.POSTGRES_USER }}\" > .env\n          echo POSTGRES_PASSWORD=\"${{ secrets.POSTGRES_PASSWORD }}\" >> .env\n          echo POSTGRES_DB=\"${{ secrets.POSTGRES_DB }}\" >> .env\n          echo DB_HOST=\"${{ secrets.DB_HOST }}\" >> .env\n          echo DB_PORT=\"${{ secrets.DB_PORT }}\" >> .env\n          echo TESTER_API_KEY=\"${{ secrets.TESTER_API_KEY }}\" >> .env\n          echo CELERY_BROKER=\"${{ secrets.CELERY_BROKER }}\" >> .env\n          echo CELERY_BACKEND=\"${{ secrets.CELERY_BACKEND }}\" >> .env\n          echo CRONJOB_BASE_URL=\"${{ secrets.CRONJOB_BASE_URL }}\" >> .env\n          echo CONSUMER_KEY=\"${{ secrets.CONSUMER_KEY }}\" >> .env\n          echo CONSUMER_SECRET=\"${{ secrets.CONSUMER_SECRET }}\" >> .env\n          echo CLIENT_ID=\"${{ secrets.CLIENT_ID }}\" >> .env\n          echo CLIENT_SECRET=\"${{ secrets.CLIENT_SECRET }}\" >> .env\n          echo ACCESS_TOKEN=\"${{ secrets.ACCESS_TOKEN }}\" >> .env\n          echo ACCESS_TOKEN_SECRET=\"${{ secrets.ACCESS_TOKEN_SECRET  }}\" >> .env\n          echo INSTAGRAM_USERNAME=\"${{ secrets.INSTAGRAM_USERNAME }}\" >> .env\n          echo INSTAGRAM_PASSWORD=\"${{ secrets.INSTAGRAM_PASSWORD }}\" >> .env\n\n\n      - name: build docker images locally\n        run: docker-compose -f docker-compose.prod.yml build --parallel\n\n      - name: run docker compose\n        run: docker-compose -f docker-compose.prod.yml up -d\n"
  },
  {
    "path": ".github/workflows/openai-pr-reviewer.yml",
    "content": "name: Code Review\n\npermissions:\n  contents: read\n  pull-requests: write\n\non:\n  pull_request:\n    branches:\n      - master\n      - main\n  pull_request_review_comment:\n    types: [created]\n\nconcurrency:\n  group:\n    ${{ github.repository }}-${{ github.event.number || github.head_ref ||\n    github.sha }}-${{ github.workflow }}-${{ github.event_name ==\n    'pull_request_review_comment' && 'pr_comment' || 'pr' }}\n  cancel-in-progress: ${{ github.event_name != 'pull_request_review_comment' }}\n\njobs:\n  review:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: fluxninja/openai-pr-reviewer@latest\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}\n        with:\n          debug: false\n          review_simple_changes: false\n          review_comment_lgtm: false\n          openai_light_model: 'gpt-3.5-turbo'\n          openai_heavy_model: 'gpt-4'\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish Packages\n\non:\n  release:\n    types: [published]\n\n\njobs:\n  release:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-python@v2\n      - run: pip install --upgrade poetry\n      - name: Publish to PyPI\n        run: poetry publish --build\n        env:\n          POETRY_HTTP_BASIC_PYPI_USERNAME: \"__token__\"\n          POETRY_HTTP_BASIC_PYPI_PASSWORD: ${{ secrets.PYPI_TOKEN }}\n      - name: Login to DockerHub\n        uses: docker/login-action@v1\n        with:\n          username: ${{ secrets.DOCKERHUB_USERNAME }}\n          password: ${{ secrets.DOCKERHUB_TOKEN }}\n      - name: Build docker images and publish\n        run: make docker-release\n"
  },
  {
    "path": ".github/workflows/quality.yml",
    "content": "name: Code Quality\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-python@v2\n      - run: pip install poetry && poetry install\n      - uses: pre-commit/action@v2.0.0\n"
  },
  {
    "path": ".gitignore",
    "content": "# Custom ignore\n.vscode\nt.*\ntest.py\nfoo.py\nrun.py\n\n# Standard python .gitignore given by GitHub\n\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\npip-wheel-metadata/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\ndb.sqlite3-journal\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# IPython\nprofile_default/\nipython_config.py\n\n# pyenv\n.python-version\n\n# pipenv\n#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.\n#   However, in case of collaboration, if having platform-specific dependencies or dependencies\n#   having no cross-platform support, pipenv may install dependencies that don't work, or not\n#   install all needed dependencies.\n#Pipfile.lock\n\n# PEP 582; used by e.g. github.com/David-OConnor/pyflow\n__pypackages__/\n\n# Celery stuff\ncelerybeat-schedule\ncelerybeat.pid\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.dmypy.json\ndmypy.json\n\n# Pyre type checker\n.pyre/\n\n# volume folder for postgres database\ndb_data\n\n# sqlite3 file\nbhagavad_gita_api/gita.db\n"
  },
  {
    "path": ".markdownlint.rb",
    "content": "all\nexclude_rule 'MD013'\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v4.0.1\n    hooks:\n      - id: trailing-whitespace\n      - id: end-of-file-fixer\n      - id: debug-statements\n\n  - repo: https://github.com/myint/autoflake\n    rev: v1.4\n    hooks:\n      - id: autoflake\n        args: ['--in-place', '--remove-unused-variable', '--ignore-init-module-imports', '--remove-all-unused-imports']\n\n  - repo: https://github.com/asottile/pyupgrade\n    rev: v2.19.4\n    hooks:\n      - id: pyupgrade\n        args: ['--py3-plus']\n\n  - repo: https://github.com/asottile/seed-isort-config\n    rev: v2.2.0\n    hooks:\n      - id: seed-isort-config\n\n  - repo: https://github.com/pre-commit/mirrors-isort\n    rev: v5.9.1\n    hooks:\n      - id: isort\n\n  - repo: https://github.com/ambv/black\n    rev: 22.3.0\n    hooks:\n      - id: black\n        language_version: python3\n\n  - repo: local\n    hooks:\n      - id: flake8\n        name: flake8\n        types: [python]\n        language: system\n        entry: poetry run flake8 --config .flake8\n        exclude: run.py\n\n  - repo: https://github.com/igorshubovych/markdownlint-cli\n    rev: v0.27.1\n    hooks:\n      - id: markdownlint\n        args: [-s, .markdownlint.rb]\n"
  },
  {
    "path": "Caddyfile",
    "content": "api.bhagavadgita.io {\n  reverse_proxy gita-api:8081  {\n    header_down Strict-Transport-Security max-age=31536000;\n   }\n}\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM python:3.9\n\nENV VENV_PATH=\"/venv\"\nENV PATH=\"$VENV_PATH/bin:$PATH\"\n\nWORKDIR /app\n\nRUN apt-get update && apt-get upgrade -y\nRUN pip install --upgrade poetry\nRUN python -m venv /venv\n\nCOPY . .\n\nRUN poetry build && \\\n    /venv/bin/pip install --upgrade pip wheel setuptools &&\\\n    /venv/bin/pip install dist/*.whl\n\nCMD bhagavad-gita-api\n"
  },
  {
    "path": "Dockerfile.dev",
    "content": "FROM python:3.9\n\nENV VENV_PATH=\"/venv\"\nENV PATH=\"$VENV_PATH/bin:$PATH\"\n\nWORKDIR /app\n\nRUN apt-get update && apt-get upgrade -y && apt-get install netcat -y\nRUN pip install --upgrade poetry\nRUN python -m venv /venv\n\nCOPY . .\n\nRUN poetry build && \\\n    /venv/bin/pip install --upgrade pip wheel setuptools && \\\n    /venv/bin/pip install dist/*.whl\n\n\nENTRYPOINT [ \"./wait_for_db.sh\" ]\n\nCMD bhagavad-gita-api\n"
  },
  {
    "path": "Dockerfile.prod",
    "content": "FROM python:3.9\n\nENV VENV_PATH=\"/venv\"\nENV PATH=\"$VENV_PATH/bin:$PATH\"\n\nWORKDIR /app\n\nRUN apt-get update && apt-get upgrade -y && apt-get install netcat -y\nRUN pip install --upgrade poetry\nRUN python -m venv /venv\n\nCOPY . .\n\nRUN poetry build && \\\n    /venv/bin/pip install --upgrade pip wheel setuptools && \\\n    /venv/bin/pip install dist/*.whl\n\n\nENTRYPOINT [ \"./wait_for_db.sh\" ]\n\nCMD gunicorn -c bhagavad_gita_api/gunicorn.conf.py bhagavad_gita_api.main:app\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 The Gita Initiative\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "# lists all available targets\nlist:\n\t@sh -c \"$(MAKE) -p no_targets__ | \\\n\t\tawk -F':' '/^[a-zA-Z0-9][^\\$$#\\/\\\\t=]*:([^=]|$$)/ {\\\n\t\t\tsplit(\\$$1,A,/ /);for(i in A)print A[i]\\\n\t\t}' | grep -v '__\\$$' | grep -v 'make\\[1\\]' | grep -v 'Makefile' | sort\"\n\n# required for list\nno_targets__:\n\nVERSION=$$(poetry version -s)\nPROJECT=\"bhagavad-gita-api\"\nDOCKER_ORG=\"bhagavadgita\"\nDOCKER_REPO=\"$(DOCKER_ORG)/$(PROJECT)\"\n\nclean:\n\t@rm -rf build dist .eggs *.egg-info\n\t@rm -rf .benchmarks .coverage coverage.xml htmlcov report.xml .tox\n\t@find . -type d -name '.mypy_cache' -exec rm -rf {} +\n\t@find . -type d -name '__pycache__' -exec rm -rf {} +\n\t@find . -type d -name '*pytest_cache*' -exec rm -rf {} +\n\t@find . -type f -name \"*.py[co]\" -exec rm -rf {} +\n\nfmt: clean\n\t@poetry run isort .\n\t@poetry run black .\n\nhard-clean: clean\n\t@rm -rf .venv\n\npypi:\n\t@poetry publish --build\n\ndocker:\n\t@docker build -t $(PROJECT) .\n\t@docker tag $(PROJECT) $(DOCKER_REPO):latest\n\t@docker tag $(PROJECT) $(DOCKER_REPO):$(VERSION)\n\ndocker-release: docker\n\t@docker push -a $(DOCKER_REPO)\n\nrelease: pypi docker-release\n"
  },
  {
    "path": "README.md",
    "content": "<!-- markdownlint-disable -->\n<p align=\"center\">\n  <a href=\"https://bhagavadgita.io\">\n    <img src=\"https://raw.githubusercontent.com/gita/bhagavad-gita-api/main/.github/gita.png\" alt=\"Logo\" width=\"300\">\n  </a>\n\n  <h3 align=\"center\">Bhagavad Gita API</h3>\n\n  <p align=\"center\">\n    Code for the BhagavadGita.io API, which is an app built for Gita readers by Gita readers.\n    <br />\n    <br />\n    <img alt=\"GitHub issues\" src=\"https://img.shields.io/github/issues/gita/bhagavad-gita-api\">\n    <img alt=\"PyPI - Python Version\" src=\"https://img.shields.io/pypi/pyversions/bhagavad-gita-api\">\n      <a href=\"https://github.com/gita/bhagavad-gita-api/blob/master/LICENSE\">\n    <img alt=\"LICENSE\" src=\"https://img.shields.io/badge/License-MIT-yellow.svg?maxAge=43200\">\n  </a>\n  <a href=\"https://github.com/gita/bhagavad-gita-api/actions/workflows/deploy.yml\"><img alt=\"Stars\" src=\"https://github.com/gita/bhagavad-gita-api/actions/workflows/deploy.yml/badge.svg\"></a>\n  <a href=\"https://api.bhagavadgita.io/docs\"><img src=\"https://img.shields.io/badge/docs-passing-green\" alt=\"Docs\"></a>\n  <a href=\"https://starcharts.herokuapp.com/gita/bhagavad-gita-api\"><img alt=\"Stars\" src=\"https://img.shields.io/github/stars/gita/bhagavad-gita-api.svg?style=social\"></a>\n</p>\n\n\n## Usage\n\nThe Bhagavad Gita API allows any developer to use content from Gita in their apps.\nThis API is built with FastAPI which is based on (and fully compatible with) the open standards for APIs: OpenAPI (previously known as Swagger) and JSON Schema.\n\nDocumentation for this API is availaible in two interactive formats:\n- [Swagger UI](https://api.bhagavadgita.io/docs)\n- [Redoc](https://api.bhagavadgita.io/redoc)\n\nIf you are interested in using this API for your application, please\nregister an account at\n[RapidAPI](https://rapidapi.com/bhagavad-gita-bhagavad-gita-default/api/bhagavad-gita3)\nwhere you'll get both the credentials as well as sample code in your language of\nchoice. The API is 100% FREE to use.\n\n## Projects\n\nHere is a list of interesting projects using this API.\n\n- [BhagavadGita.io](https://bhagavadgita.io)\n- [Android App](https://play.google.com/store/apps/details?id=com.hanuman.bhagavadgita)\n\nHave you build something with this API ? Open a \"Show and tell\" discussion. The maintainers will feature your project on the README if they find it interesting.\n\n## Self Hosting\n<!-- markdownlint-enable -->\n\nThe official API is free to use for all.\nBut If you wish you can self host anywhere you want.\n\nIf you want to deploy your own instance,You can deploy\nthe API server on your system or VPS.\n\n- Using [`pipx`](https://pypa.github.io/pipx/installation/)\n  > **Note** If you dont have `pipx`, just `pip install pipx`\n\n    ```shell\n    pipx run bhagavad-gita-api\n    ```\n\n- Or using [`docker`](https://www.docker.com/)\n\n    ```shell\n    docker run -it -p 8081:8081 --env-file=.env bhagavadgita/bhagavad-gita-api\n    ```\n\n<!-- markdownlint-disable -->\nNow open http://localhost:8081/docs to see docs.\nTo stop the server press <kbd>Ctrl</kbd> + <kbd>C</kbd> on your keyboard.\n<!-- markdownlint-enable -->\n\nBy default an in-memory SQLite database is used.\nBut you configure to use any SQL database of your choice.\nThe official version uses PostgreSQL.\n\nLooking to deploy on a cloud platform ?\nWe have detailed docs to deploy to the following platforms:\n\n- [Heroku](https://github.com/gita/bhagavad-gita-api/wiki/Heroku)\n- [Deta](https://github.com/gita/bhagavad-gita-api/wiki/Deta)\n- [Digital Ocean](https://github.com/gita/bhagavad-gita-api/wiki/Digial-Ocean)\n\n## Configuration\n\nHere is the list of supported environment variables.\n\n<!-- markdownlint-disable -->\n| Name                      | Description                           | Default     |\n| ------------------------- | ------------------------------------- | ----------- |\n| `TESTER_API_KEY`          | The API key for testing.              | `None`      |\n| `SQLALCHEMY_DATABASE_URI` | The DSN for your database connection. | `sqlite://` (in memory SQLite db)|\n<!-- markdownlint-enable -->\n\nIf you want to configure your deployment even more,\nthen please take a look at module [`config.py`](bhagavad_gita_api/config.py).\n\nTo set the environment variables, you may simply use a `.env` file where you\nspecify the values in the format of `KEY=VALUE`.\n\n## Development\n\nFeel free to use the [issue tracker](https://github.com/gita/bhagavad-gita-api/issues)\nfor bugs and feature requests.\n\nLooking to contribute code ? PRs are most welcome!\nTo get started with developing this API, please read the [contributing guide](.github/CONTRIBUTING.md).\n\n## Community\n\nJoin the [Discord chat server](https://discord.gg/gX8dstApZX) and\nhang out with others in the community.\n\nYou can also use [GitHub Discussions](https://github.com/gita/bhagavad-gita-api/discussions)\nto ask questions or tell us about\nprojects you have built using this API.\n\n## Contributors ✨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tr>\n    <td align=\"center\"><a href=\"https://github.com/Gupta-Anubhav12\"><img src=\"https://avatars.githubusercontent.com/u/64721638?v=4?s=100\" width=\"100px;\" alt=\"\"/><br /><sub><b>Anubhav Gupta</b></sub></a><br /><a href=\"https://github.com/gita/bhagavad-gita-api/commits?author=Gupta-Anubhav12\" title=\"Code\">💻</a></td>\n    <td align=\"center\"><a href=\"https://github.com/sanujsood\"><img src=\"https://avatars.githubusercontent.com/u/67072668?v=4?s=100\" width=\"100px;\" alt=\"\"/><br /><sub><b>Sanuj Sood</b></sub></a><br /><a href=\"https://github.com/gita/bhagavad-gita-api/commits?author=sanujsood\" title=\"Code\">💻</a></td>\n    <td align=\"center\"><a href=\"http://aahnik.dev\"><img src=\"https://avatars.githubusercontent.com/u/66209958?v=4?s=100\" width=\"100px;\" alt=\"\"/><br /><sub><b>Aahnik Daw</b></sub></a><br /><a href=\"https://github.com/gita/bhagavad-gita-api/commits?author=aahnik\" title=\"Code\">💻</a></td>\n    <td align=\"center\"><a href=\"https://github.com/akshatj2209\"><img src=\"https://avatars.githubusercontent.com/u/57488922?v=4?s=100\" width=\"100px;\" alt=\"\"/><br /><sub><b>Akshat Joshi</b></sub></a><br /><a href=\"https://github.com/gita/bhagavad-gita-api/commits?author=akshatj2209\" title=\"Code\">💻</a></td>\n    <td align=\"center\"><a href=\"https://www.realdevils.com/\"><img src=\"https://avatars.githubusercontent.com/u/60562606?v=4?s=100\" width=\"100px;\" alt=\"\"/><br /><sub><b>Amritpal Singh</b></sub></a><br /><a href=\"https://github.com/gita/bhagavad-gita-api/commits?author=Amritpal2001\" title=\"Code\">💻</a></td>\n    <td align=\"center\"><a href=\"https://github.com/NIKU-SINGH\"><img src=\"https://avatars.githubusercontent.com/u/72123526?v=4?s=100\" width=\"100px;\" alt=\"\"/><br /><sub><b>Niku Singh</b></sub></a><br /><a href=\"https://github.com/gita/bhagavad-gita-api/commits?author=NIKU-SINGH\" title=\"Code\">💻</a></td>\n    <td align=\"center\"><a href=\"https://sreevardhanreddi.github.io/\"><img src=\"https://avatars.githubusercontent.com/u/31174432?v=4?s=100\" width=\"100px;\" alt=\"\"/><br /><sub><b>sreevardhanreddi</b></sub></a><br /><a href=\"https://github.com/gita/bhagavad-gita-api/commits?author=sreevardhanreddi\" title=\"Code\">💻</a> <a href=\"#infra-sreevardhanreddi\" title=\"Infrastructure (Hosting, Build-Tools, etc)\">🚇</a></td>\n  </tr>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors)\nspecification. Contributions of any kind welcome!\n"
  },
  {
    "path": "bhagavad_gita_api/MyIGBot.py",
    "content": "# flake8: noqa\nimport json\nimport os\nimport random\nimport string\nimport time\nfrom datetime import datetime\n\nimport requests\nfrom bs4 import BeautifulSoup as bs\n\n\nclass bcolors:\n    HEADER = \"\\033[95m\"\n    OKBLUE = \"\\033[94m\"\n    OKCYAN = \"\\033[96m\"\n    OKGREEN = \"\\033[92m\"\n    WARNING = \"\\033[93m\"\n    FAIL = \"\\033[91m\"\n    ENDC = \"\\033[0m\"\n    BOLD = \"\\033[1m\"\n    UNDERLINE = \"\\033[4m\"\n\n\nclass MyIGBot:\n    def __init__(self, username, password, use_cookie=True, proxy=None):\n        self.username = username\n        self.password = password\n        self.use_cookie = use_cookie\n        self.proxy = proxy\n\n        self.path = os.getcwd()\n\n        if (\n            use_cookie == False\n            or os.path.exists(self.path + f\"//cookie_{self.username}.bot\") == False\n        ):\n            link = \"https://www.instagram.com/\"\n            login_url = \"https://www.instagram.com/accounts/login/ajax/\"\n\n            time_now = int(datetime.now().timestamp())\n            response = requests.get(link, proxies=self.proxy)\n            try:\n                csrf = response.cookies[\"csrftoken\"]\n            except:\n                letters = string.ascii_lowercase\n                csrf = \"\".join(random.choice(letters) for i in range(8))\n\n            payload = {\n                \"username\": self.username,\n                \"enc_password\": f\"#PWD_INSTAGRAM_BROWSER:0:{time_now}:{self.password}\",\n                \"queryParams\": {},\n                \"optIntoOneTap\": \"false\",\n            }\n\n            login_header = {\n                \"User-Agent\": \"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36\",\n                \"X-Requested-With\": \"XMLHttpRequest\",\n                \"Referer\": \"https://www.instagram.com/accounts/login/\",\n                \"x-csrftoken\": csrf,\n            }\n\n            login_response = requests.post(\n                login_url, data=payload, headers=login_header, proxies=self.proxy\n            )\n            json_data = json.loads(login_response.text)\n\n            cookies = login_response.cookies\n            cookie_jar = cookies.get_dict()\n            try:\n                self.csrf_token = cookie_jar[\"csrftoken\"]\n            except:\n                self.csrf_token = csrf\n\n            try:\n                if json_data[\"authenticated\"]:\n                    pass\n                else:\n                    print(\n                        bcolors.FAIL + \"[✗] Login Failed!\" + bcolors.ENDC,\n                        login_response.text,\n                    )\n                    quit()\n            except KeyError:\n                try:\n                    if json_data[\"two_factor_required\"]:\n                        self.ig_nrcb = cookie_jar[\"ig_nrcb\"]\n                        self.ig_did = cookie_jar[\"ig_did\"]\n                        self.mid = cookie_jar[\"mid\"]\n\n                        otp = input(\n                            bcolors.OKBLUE\n                            + \"[!] Two Factor Auth. Detected! Enter Code Here: \"\n                            + bcolors.ENDC\n                        )\n                        twofactor_url = (\n                            \"https://www.instagram.com/accounts/login/ajax/two_factor/\"\n                        )\n                        twofactor_payload = {\n                            \"username\": self.username,\n                            \"verificationCode\": otp,\n                            \"identifier\": json_data[\"two_factor_info\"][\n                                \"two_factor_identifier\"\n                            ],\n                            \"queryParams\": {},\n                        }\n\n                        twofactor_header = {\n                            \"accept\": \"*/*\",\n                            \"accept-encoding\": \"gzip, deflate, br\",\n                            \"accept-language\": \"en-US,en;q=0.9\",\n                            \"content-type\": \"application/x-www-form-urlencoded\",\n                            \"cookie\": \"ig_did=\"\n                            + self.ig_did\n                            + \"; ig_nrcb=\"\n                            + self.ig_nrcb\n                            + \"; csrftoken=\"\n                            + self.csrf_token\n                            + \"; mid=\"\n                            + self.mid,\n                            \"origin\": \"https://www.instagram.com\",\n                            \"referer\": \"https://www.instagram.com/accounts/login/two_factor?next=%2F\",\n                            \"sec-fetch-dest\": \"empty\",\n                            \"sec-fetch-mode\": \"cors\",\n                            \"sec-fetch-site\": \"same-origin\",\n                            \"user-agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36\",\n                            \"x-csrftoken\": self.csrf_token,\n                            \"x-ig-app-id\": \"936619743392459\",\n                            \"x-ig-www-claim\": \"0\",\n                            \"x-instagram-ajax\": \"00c4537694a4\",\n                            \"x-requested-with\": \"XMLHttpRequest\",\n                        }\n\n                        login_response = requests.post(\n                            twofactor_url,\n                            data=twofactor_payload,\n                            headers=twofactor_header,\n                            proxies=self.proxy,\n                        )\n                        try:\n                            if login_response.headers[\"Set-Cookie\"] != 0:\n                                pass\n                        except:\n                            try:\n                                if json_data[\"message\"] == \"checkpoint_required\":\n                                    self.ig_nrcb = cookie_jar[\"ig_nrcb\"]\n                                    self.ig_did = cookie_jar[\"ig_did\"]\n                                    self.mid = cookie_jar[\"mid\"]\n                                    url = (\n                                        \"https://www.instagram.com\"\n                                        + json_data[\"checkpoint_url\"]\n                                    )\n                                    header = {\n                                        \"accept\": \"*/*\",\n                                        \"accept-encoding\": \"gzip, deflate, br\",\n                                        \"accept-language\": \"en-US,en;q=0.9\",\n                                        \"content-type\": \"application/x-www-form-urlencoded\",\n                                        \"cookie\": \"ig_did=\"\n                                        + self.ig_did\n                                        + \"; ig_nrcb=\"\n                                        + self.ig_nrcb\n                                        + \"; csrftoken=\"\n                                        + self.csrf_token\n                                        + \"; mid=\"\n                                        + self.mid,\n                                        \"origin\": \"https://www.instagram.com\",\n                                        \"referer\": \"https://instagram.com\"\n                                        + json_data[\"checkpoint_url\"],\n                                        \"sec-fetch-dest\": \"empty\",\n                                        \"sec-fetch-mode\": \"cors\",\n                                        \"sec-fetch-site\": \"same-origin\",\n                                        \"user-agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36\",\n                                        \"x-csrftoken\": self.csrf_token,\n                                        \"x-ig-app-id\": \"936619743392459\",\n                                        \"x-ig-www-claim\": \"0\",\n                                        \"x-instagram-ajax\": \"e8e20d8ba618\",\n                                        \"x-requested-with\": \"XMLHttpRequest\",\n                                    }\n                                    code = input(\n                                        bcolors.OKBLUE\n                                        + json.loads(\n                                            requests.post(\n                                                url,\n                                                headers=header,\n                                                data={\"choice\": \"1\"},\n                                            ).text,\n                                            proxies=self.proxy,\n                                        )[\"extraData\"][\"content\"][1][\"text\"]\n                                        + \" > \"\n                                        + bcolors.ENDC\n                                    )\n                                    if (\n                                        json.loads(\n                                            requests.post(\n                                                url,\n                                                headers=header,\n                                                data={\"security_code\": code},\n                                            ).text,\n                                            proxies=self.proxy,\n                                        )[\"type\"]\n                                        == \"CHALLENGE_REDIRECTION\"\n                                    ):\n                                        login_response = requests.post(\n                                            login_url,\n                                            data=payload,\n                                            headers=login_header,\n                                            proxies=self.proxy,\n                                        )\n                                    else:\n                                        print(\n                                            bcolors.FAIL\n                                            + \"[✗] Login Failed!\"\n                                            + bcolors.ENDC\n                                        )\n                                        quit()\n                            except:\n                                print(bcolors.FAIL + \"[✗] Login Failed!\" + bcolors.ENDC)\n                                quit()\n\n                except KeyError:\n                    try:\n                        if json_data[\"message\"] == \"checkpoint_required\":\n                            self.ig_nrcb = cookie_jar[\"ig_nrcb\"]\n                            self.ig_did = cookie_jar[\"ig_did\"]\n                            self.mid = cookie_jar[\"mid\"]\n                            url = (\n                                \"https://www.instagram.com\"\n                                + json_data[\"checkpoint_url\"]\n                            )\n                            header = {\n                                \"accept\": \"*/*\",\n                                \"accept-encoding\": \"gzip, deflate, br\",\n                                \"accept-language\": \"en-US,en;q=0.9\",\n                                \"content-type\": \"application/x-www-form-urlencoded\",\n                                \"cookie\": \"ig_did=\"\n                                + self.ig_did\n                                + \"; ig_nrcb=\"\n                                + self.ig_nrcb\n                                + \"; csrftoken=\"\n                                + self.csrf_token\n                                + \"; mid=\"\n                                + self.mid,\n                                \"origin\": \"https://www.instagram.com\",\n                                \"referer\": \"https://instagram.com\"\n                                + json_data[\"checkpoint_url\"],\n                                \"sec-fetch-dest\": \"empty\",\n                                \"sec-fetch-mode\": \"cors\",\n                                \"sec-fetch-site\": \"same-origin\",\n                                \"user-agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36\",\n                                \"x-csrftoken\": self.csrf_token,\n                                \"x-ig-app-id\": \"936619743392459\",\n                                \"x-ig-www-claim\": \"0\",\n                                \"x-instagram-ajax\": \"e8e20d8ba618\",\n                                \"x-requested-with\": \"XMLHttpRequest\",\n                            }\n                            code = input(\n                                bcolors.OKBLUE\n                                + json.loads(\n                                    requests.post(\n                                        url, headers=header, data={\"choice\": \"1\"}\n                                    ).text,\n                                    proxies=self.proxy,\n                                )[\"extraData\"][\"content\"][1][\"text\"]\n                                + \" > \"\n                                + bcolors.ENDC\n                            )\n                            if (\n                                json.loads(\n                                    requests.post(\n                                        url,\n                                        headers=header,\n                                        data={\"security_code\": code},\n                                    ).text,\n                                    proxies=self.proxy,\n                                )[\"type\"]\n                                == \"CHALLENGE_REDIRECTION\"\n                            ):\n                                login_response = requests.post(\n                                    login_url,\n                                    data=payload,\n                                    headers=login_header,\n                                    proxies=self.proxy,\n                                )\n                            else:\n                                print(bcolors.FAIL + \"[✗] Login Failed!\" + bcolors.ENDC)\n                                quit()\n                    except:\n                        print(bcolors.FAIL + \"[✗] Login Failed!\" + bcolors.ENDC)\n                        quit()\n\n            self.sessionid = (\n                login_response.headers[\"Set-Cookie\"]\n                .split(\"sessionid=\")[1]\n                .split(\";\")[0]\n            )\n            self.userId = (\n                login_response.headers[\"Set-Cookie\"]\n                .split(\"ds_user_id=\")[1]\n                .split(\";\")[0]\n            )\n            self.cookie = (\n                \"sessionid=\"\n                + self.sessionid\n                + \"; csrftoken=\"\n                + self.csrf_token\n                + \"; ds_user_id=\"\n                + self.userId\n                + \";\"\n            )\n            create_cookie = open(\n                self.path + f\"//cookie_{self.username}.bot\", \"w+\", encoding=\"utf-8\"\n            )\n            create_cookie.write(self.cookie)\n            create_cookie.close()\n            self.session = requests.session()\n            cookie_obj = requests.cookies.create_cookie(\n                name=\"sessionid\", secure=True, value=self.sessionid\n            )\n            self.session.cookies.set_cookie(cookie_obj)\n\n        elif os.path.exists(self.path + f\"//cookie_{self.username}.bot\"):\n            try:\n                read_cookie = open(\n                    self.path + f\"//cookie_{self.username}.bot\", encoding=\"utf-8\"\n                )\n                self.cookie = read_cookie.read()\n                read_cookie.close()\n                homelink = \"https://www.instagram.com/op/\"\n                self.session = requests.session()\n                self.sessionid = self.cookie.split(\"=\")[1].split(\";\")[0]\n                self.csrf_token = self.cookie.split(\"=\")[2].split(\";\")[0]\n                cookie_obj = requests.cookies.create_cookie(\n                    name=\"sessionid\", secure=True, value=self.sessionid\n                )\n                self.session.cookies.set_cookie(cookie_obj)\n                login_response = self.session.get(homelink, proxies=self.proxy)\n                time.sleep(1)\n                soup = bs(login_response.text, \"html.parser\")\n                soup.find(\n                    \"strong\",\n                    {\n                        \"class\": \"-cx-PRIVATE-NavBar__username -cx-PRIVATE-NavBar__username__\"\n                    },\n                ).get_text()\n            except AttributeError:\n                print(\n                    bcolors.FAIL\n                    + \"[✗] Login Failed! Cookie file is corupted!\"\n                    + bcolors.ENDC\n                )\n                os.remove(self.path + f\"//cookie_{self.username}.bot\")\n                print(\n                    bcolors.WARNING\n                    + \"[-] Deleted Corupted Cookie File! Try Again!\"\n                    + bcolors.ENDC\n                )\n                quit()\n\n    def already_liked(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        resp = self.session.get(post_link, proxies=self.proxy)\n        time.sleep(1)\n        soup = bs(resp.text, \"html.parser\")\n        scripts = soup.find_all(\"script\")\n        data_script = str(scripts[15])\n        time.sleep(1)\n        try:\n            shortcode = post_link.split(\"/p/\")[1].replace(\"/\", \"\")\n            data_script = data_script.replace(\n                f\"\"\"<script type=\"text/javascript\">window.__additionalDataLoaded('/p/{shortcode}/',\"\"\",\n                \"\",\n            )\n        except:\n            shortcode = post_link.split(\"/tv/\")[1].replace(\"/\", \"\")\n            data_script = data_script.replace(\n                f\"\"\"<script type=\"text/javascript\">window.__additionalDataLoaded('/tv/{shortcode}/',\"\"\",\n                \"\",\n            )\n        data_object = data_script.replace(\");</script>\", \"\")\n        data_json = json.loads(data_object)\n        liked = data_json[\"graphql\"][\"shortcode_media\"][\"viewer_has_liked\"]\n\n        return bool(liked)\n\n    def like(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        try:\n            if self.already_liked(post_link) == False:\n                resp = self.session.get(post_link, proxies=self.proxy)\n                time.sleep(1)\n                soup = bs(resp.text, \"html.parser\")\n                scripts = soup.find_all(\"script\")\n                data_script = str(scripts[15])\n                time.sleep(1)\n                try:\n                    shortcode = post_link.split(\"/p/\")[1].replace(\"/\", \"\")\n                    data_script = data_script.replace(\n                        f\"\"\"<script type=\"text/javascript\">window.__additionalDataLoaded('/p/{shortcode}/',\"\"\",\n                        \"\",\n                    )\n                except:\n                    shortcode = post_link.split(\"/tv/\")[1].replace(\"/\", \"\")\n                    data_script = data_script.replace(\n                        f\"\"\"<script type=\"text/javascript\">window.__additionalDataLoaded('/tv/{shortcode}/',\"\"\",\n                        \"\",\n                    )\n                data_object = data_script.replace(\");</script>\", \"\")\n                data_json = json.loads(data_object)\n                id_post = data_json[\"graphql\"][\"shortcode_media\"][\"id\"]\n\n                url_post = f\"https://www.instagram.com/web/likes/{id_post}/like/\"\n\n                headers = {\n                    \"accept\": \"*/*\",\n                    \"accept-encoding\": \"gzip, deflate, br\",\n                    \"accept-language\": \"en-US,en;q=0.9\",\n                    \"content-length\": \"0\",\n                    \"content-type\": \"application/x-www-form-urlencoded\",\n                    \"cookie\": self.cookie,\n                    \"origin\": \"https://www.instagram.com\",\n                    \"referer\": post_link,\n                    \"sec-fetch-dest\": \"empty\",\n                    \"sec-fetch-mode\": \"cors\",\n                    \"sec-fetch-site\": \"same-origin\",\n                    \"user-agent\": \"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36\",\n                    \"x-csrftoken\": self.csrf_token,\n                    \"x-ig-app-id\": \"936619743392459\",\n                    \"x-ig-www-claim\": \"hmac.AR3dC7naiVtTKkwrEY0hwTO9zj4kLxfvf4Srvp3wFyoZFqSx\",\n                    \"x-instagram-ajax\": \"d3d3aea32e75\",\n                    \"x-requested-with\": \"XMLHttpRequest\",\n                }\n                response = requests.request(\n                    \"POST\", url_post, headers=headers, proxies=self.proxy\n                )\n\n                if response.status_code != 200:\n                    return response.status_code\n            else:\n                return 208\n        except:\n            return 403\n\n        return 200\n\n    def unlike(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        try:\n            if self.already_liked(post_link) == True:\n                resp = self.session.get(post_link, proxies=self.proxy)\n                time.sleep(1)\n                soup = bs(resp.text, \"html.parser\")\n                scripts = soup.find_all(\"script\")\n                data_script = str(scripts[15])\n                time.sleep(1)\n                try:\n                    shortcode = post_link.split(\"/p/\")[1].replace(\"/\", \"\")\n                    data_script = data_script.replace(\n                        f\"\"\"<script type=\"text/javascript\">window.__additionalDataLoaded('/p/{shortcode}/',\"\"\",\n                        \"\",\n                    )\n                except:\n                    shortcode = post_link.split(\"/tv/\")[1].replace(\"/\", \"\")\n                    data_script = data_script.replace(\n                        f\"\"\"<script type=\"text/javascript\">window.__additionalDataLoaded('/tv/{shortcode}/',\"\"\",\n                        \"\",\n                    )\n                data_object = data_script.replace(\");</script>\", \"\")\n                data_json = json.loads(data_object)\n                id_post = data_json[\"graphql\"][\"shortcode_media\"][\"id\"]\n\n                url_post = f\"https://www.instagram.com/web/likes/{id_post}/unlike/\"\n\n                headers = {\n                    \"accept\": \"*/*\",\n                    \"accept-encoding\": \"gzip, deflate, br\",\n                    \"accept-language\": \"en-US,en;q=0.9\",\n                    \"content-length\": \"0\",\n                    \"content-type\": \"application/x-www-form-urlencoded\",\n                    \"cookie\": self.cookie,\n                    \"origin\": \"https://www.instagram.com\",\n                    \"referer\": post_link,\n                    \"sec-fetch-dest\": \"empty\",\n                    \"sec-fetch-mode\": \"cors\",\n                    \"sec-fetch-site\": \"same-origin\",\n                    \"user-agent\": \"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36\",\n                    \"x-csrftoken\": self.csrf_token,\n                    \"x-ig-app-id\": \"936619743392459\",\n                    \"x-ig-www-claim\": \"hmac.AR3dC7naiVtTKkwrEY0hwTO9zj4kLxfvf4Srvp3wFyoZFqSx\",\n                    \"x-instagram-ajax\": \"d3d3aea32e75\",\n                    \"x-requested-with\": \"XMLHttpRequest\",\n                }\n                response = requests.request(\n                    \"POST\", url_post, headers=headers, proxies=self.proxy\n                )\n\n                if response.status_code != 200:\n                    return response.status_code\n            else:\n                return 208\n\n        except:\n            return 403\n\n        return 200\n\n    def like_recent(self, username):\n        resp = self.session.get(\n            \"https://www.instagram.com/\" + username + \"/\", proxies=self.proxy\n        )\n        time.sleep(1)\n        soup = bs(resp.text, \"html.parser\")\n        scripts = soup.find_all(\"script\")\n        try:\n            data_script = str(scripts[4])\n            time.sleep(1)\n            data_script = data_script.replace(\n                \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n            )\n            data_object = data_script.replace(\";</script>\", \"\")\n            data_json = json.loads(data_object)\n        except:\n            data_script = str(scripts[3])\n            time.sleep(1)\n            data_script = data_script.replace(\n                \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n            )\n            data_object = data_script.replace(\";</script>\", \"\")\n            data_json = json.loads(data_object)\n        try:\n            shortcode = data_json[\"entry_data\"][\"ProfilePage\"][0][\"graphql\"][\"user\"][\n                \"edge_owner_to_timeline_media\"\n            ][\"edges\"][0][\"node\"][\"shortcode\"]\n            return self.like(\"https://www.instagram.com/p/\" + shortcode + \"/\")\n        except IndexError:\n            return 404\n        except KeyError:\n            return 404\n\n    def comment(self, post_link, comment_text):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        try:\n            resp = self.session.get(post_link, proxies=self.proxy)\n            time.sleep(1)\n            soup = bs(resp.text, \"html.parser\")\n            scripts = soup.find_all(\"script\")\n            data_script = str(scripts[15])\n            time.sleep(1)\n            try:\n                shortcode = post_link.split(\"/p/\")[1].replace(\"/\", \"\")\n                data_script = data_script.replace(\n                    f\"\"\"<script type=\"text/javascript\">window.__additionalDataLoaded('/p/{shortcode}/',\"\"\",\n                    \"\",\n                )\n            except:\n                shortcode = post_link.split(\"/tv/\")[1].replace(\"/\", \"\")\n                data_script = data_script.replace(\n                    f\"\"\"<script type=\"text/javascript\">window.__additionalDataLoaded('/tv/{shortcode}/',\"\"\",\n                    \"\",\n                )\n            data_object = data_script.replace(\");</script>\", \"\")\n            data_json = json.loads(data_object)\n            id_post = data_json[\"graphql\"][\"shortcode_media\"][\"id\"]\n\n            url_post = f\"https://www.instagram.com/web/comments/{id_post}/add/\"\n\n            headers = {\n                \"accept\": \"*/*\",\n                \"accept-encoding\": \"gzip, deflate, br\",\n                \"accept-language\": \"en-US,en;q=0.9\",\n                \"content-length\": \"39\",\n                \"content-type\": \"application/x-www-form-urlencoded\",\n                \"cookie\": self.cookie,\n                \"origin\": \"https://www.instagram.com\",\n                \"referer\": post_link,\n                \"sec-fetch-dest\": \"empty\",\n                \"sec-fetch-mode\": \"cors\",\n                \"sec-fetch-site\": \"same-origin\",\n                \"user-agent\": \"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36\",\n                \"x-csrftoken\": self.csrf_token,\n                \"x-ig-app-id\": \"936619743392459\",\n                \"x-ig-www-claim\": \"hmac.AR3dC7naiVtTKkwrEY0hwTO9zj4kLxfvf4Srvp3wFyoZFvZV\",\n                \"x-instagram-ajax\": \"d3d3aea32e75\",\n                \"x-requested-with\": \"XMLHttpRequest\",\n            }\n\n            response = requests.request(\n                \"POST\",\n                url_post,\n                headers=headers,\n                data=f\"comment_text={comment_text}&replied_to_comment_id=\".encode(\n                    \"utf-8\"\n                ),\n                proxies=self.proxy,\n            )\n\n            if response.status_code != 200:\n                return response.status_code\n        except:\n            return 403\n\n        return 200\n\n    def comment_recent(self, username, comment_text):\n        resp = self.session.get(\n            \"https://www.instagram.com/\" + username + \"/\", proxies=self.proxy\n        )\n        time.sleep(1)\n        soup = bs(resp.text, \"html.parser\")\n        scripts = soup.find_all(\"script\")\n        try:\n            data_script = str(scripts[4])\n            time.sleep(1)\n            data_script = data_script.replace(\n                \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n            )\n            data_object = data_script.replace(\";</script>\", \"\")\n            data_json = json.loads(data_object)\n        except:\n            data_script = str(scripts[3])\n            time.sleep(1)\n            data_script = data_script.replace(\n                \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n            )\n            data_object = data_script.replace(\";</script>\", \"\")\n            data_json = json.loads(data_object)\n        try:\n            shortcode = data_json[\"entry_data\"][\"ProfilePage\"][0][\"graphql\"][\"user\"][\n                \"edge_owner_to_timeline_media\"\n            ][\"edges\"][0][\"node\"][\"shortcode\"]\n            return self.comment(\n                \"https://www.instagram.com/p/\" + shortcode + \"/\", comment_text\n            )\n        except IndexError:\n            return 404\n        except KeyError:\n            return 404\n\n    def already_followed(self, username):\n        resp = self.session.get(\n            \"https://www.instagram.com/\" + username + \"/\", proxies=self.proxy\n        )\n        time.sleep(1)\n        soup = bs(resp.text, \"html.parser\")\n        scripts = soup.find_all(\"script\")\n        try:\n            data_script = str(scripts[4])\n            time.sleep(1)\n            data_script = data_script.replace(\n                \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n            )\n            data_object = data_script.replace(\";</script>\", \"\")\n            data_json = json.loads(data_object)\n        except:\n            data_script = str(scripts[3])\n            time.sleep(1)\n            data_script = data_script.replace(\n                \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n            )\n            data_object = data_script.replace(\";</script>\", \"\")\n            data_json = json.loads(data_object)\n        followed = data_json[\"entry_data\"][\"ProfilePage\"][0][\"graphql\"][\"user\"][\n            \"followed_by_viewer\"\n        ]\n        return bool(followed)\n\n    def follow(self, username):\n        try:\n            if self.already_followed(username) == False:\n                resp = self.session.get(\n                    \"https://www.instagram.com/\" + username + \"/\", proxies=self.proxy\n                )\n                time.sleep(1)\n                soup = bs(resp.text, \"html.parser\")\n                scripts = soup.find_all(\"script\")\n                try:\n                    data_script = str(scripts[4])\n                    time.sleep(1)\n                    data_script = data_script.replace(\n                        \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n                    )\n                    data_object = data_script.replace(\";</script>\", \"\")\n                    data_json = json.loads(data_object)\n                except:\n                    data_script = str(scripts[3])\n                    time.sleep(1)\n                    data_script = data_script.replace(\n                        \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n                    )\n                    data_object = data_script.replace(\";</script>\", \"\")\n                    data_json = json.loads(data_object)\n                id_page = data_json[\"entry_data\"][\"ProfilePage\"][0][\"graphql\"][\"user\"][\n                    \"id\"\n                ]\n\n                url_page = (\n                    f\"https://www.instagram.com/web/friendships/{id_page}/follow/\"\n                )\n\n                headers = {\n                    \"accept\": \"*/*\",\n                    \"accept-encoding\": \"gzip, deflate, br\",\n                    \"accept-language\": \"en-US,en;q=0.9\",\n                    \"content-length\": \"0\",\n                    \"content-type\": \"application/x-www-form-urlencoded\",\n                    \"cookie\": self.cookie,\n                    \"origin\": \"https://www.instagram.com\",\n                    \"referer\": f\"https://www.instagram.com/{username}/\",\n                    \"sec-fetch-dest\": \"empty\",\n                    \"sec-fetch-mode\": \"cors\",\n                    \"sec-fetch-site\": \"same-origin\",\n                    \"user-agent\": \"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36\",\n                    \"x-csrftoken\": self.csrf_token,\n                    \"x-ig-app-id\": \"936619743392459\",\n                    \"x-ig-www-claim\": \"hmac.AR3dC7naiVtTKkwrEY0hwTO9zj4kLxfvf4Srvp3wFyoZFvZV\",\n                    \"x-instagram-ajax\": \"d3d3aea32e75\",\n                    \"x-requested-with\": \"XMLHttpRequest\",\n                }\n\n                response = requests.request(\n                    \"POST\", url_page, headers=headers, proxies=self.proxy\n                )\n                if response.status_code == 200:\n                    return 200\n                else:\n                    return response.status_code\n            else:\n                return 208\n\n        except KeyError:\n            return 404\n\n    def unfollow(self, username):\n        try:\n            if self.already_followed(username) == True:\n                resp = self.session.get(\n                    \"https://www.instagram.com/\" + username + \"/\", proxies=self.proxy\n                )\n                time.sleep(1)\n                soup = bs(resp.text, \"html.parser\")\n                scripts = soup.find_all(\"script\")\n                try:\n                    data_script = str(scripts[4])\n                    time.sleep(1)\n                    data_script = data_script.replace(\n                        \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n                    )\n                    data_object = data_script.replace(\";</script>\", \"\")\n                    data_json = json.loads(data_object)\n                except:\n                    data_script = str(scripts[3])\n                    time.sleep(1)\n                    data_script = data_script.replace(\n                        \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n                    )\n                    data_object = data_script.replace(\";</script>\", \"\")\n                    data_json = json.loads(data_object)\n                id_page = data_json[\"entry_data\"][\"ProfilePage\"][0][\"graphql\"][\"user\"][\n                    \"id\"\n                ]\n\n                url_page = (\n                    f\"https://www.instagram.com/web/friendships/{id_page}/unfollow/\"\n                )\n\n                headers = {\n                    \"accept\": \"*/*\",\n                    \"accept-encoding\": \"gzip, deflate, br\",\n                    \"accept-language\": \"en-US,en;q=0.9\",\n                    \"content-length\": \"0\",\n                    \"content-type\": \"application/x-www-form-urlencoded\",\n                    \"cookie\": self.cookie,\n                    \"origin\": \"https://www.instagram.com\",\n                    \"referer\": f\"https://www.instagram.com/{username}/\",\n                    \"sec-fetch-dest\": \"empty\",\n                    \"sec-fetch-mode\": \"cors\",\n                    \"sec-fetch-site\": \"same-origin\",\n                    \"user-agent\": \"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36\",\n                    \"x-csrftoken\": self.csrf_token,\n                    \"x-ig-app-id\": \"936619743392459\",\n                    \"x-ig-www-claim\": \"hmac.AR3dC7naiVtTKkwrEY0hwTO9zj4kLxfvf4Srvp3wFyoZFvZV\",\n                    \"x-instagram-ajax\": \"d3d3aea32e75\",\n                    \"x-requested-with\": \"XMLHttpRequest\",\n                }\n\n                response = requests.request(\n                    \"POST\", url_page, headers=headers, proxies=self.proxy\n                )\n                if response.status_code == 200:\n                    return 200\n                else:\n                    return response.status_code\n            else:\n                return 208\n        except KeyError:\n            return 404\n\n    def story_view(self, username):\n        try:\n            resp = self.session.get(\n                \"https://www.instagram.com/\" + username + \"/\", proxies=self.proxy\n            )\n            time.sleep(1)\n            soup = bs(resp.text, \"html.parser\")\n            scripts = soup.find_all(\"script\")\n            try:\n                data_script = str(scripts[4])\n                time.sleep(1)\n                data_script = data_script.replace(\n                    \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n                )\n                data_object = data_script.replace(\";</script>\", \"\")\n                data_json = json.loads(data_object)\n            except:\n                try:\n                    data_script = str(scripts[3])\n                    time.sleep(1)\n                    data_script = data_script.replace(\n                        \"\"\"<script type=\"text/javascript\">window._sharedData = \"\"\", \"\"\n                    )\n                    data_object = data_script.replace(\";</script>\", \"\")\n                    data_json = json.loads(data_object)\n                except:\n                    return 404\n            page_id = data_json[\"entry_data\"][\"ProfilePage\"][0][\"graphql\"][\"user\"][\"id\"]\n            surl = f\"https://www.instagram.com/graphql/query/?query_hash=c9c56db64beb4c9dea2d17740d0259d9&variables=%7B%22reel_ids%22%3A%5B%22{page_id}%22%5D%2C%22tag_names%22%3A%5B%5D%2C%22location_ids%22%3A%5B%5D%2C%22highlight_reel_ids%22%3A%5B%5D%2C%22precomposed_overlay%22%3Afalse%2C%22show_story_viewer_list%22%3Atrue%2C%22story_viewer_fetch_count%22%3A50%2C%22story_viewer_cursor%22%3A%22%22%2C%22stories_video_dash_manifest%22%3Afalse%7D\"\n            resp = self.session.get(surl, proxies=self.proxy)\n            time.sleep(1)\n            soup = bs(resp.text, \"html.parser\")\n            data_json = json.loads(str(soup))\n            story_count = len(data_json[\"data\"][\"reels_media\"][0][\"items\"])\n\n            for i in range(0, story_count):\n                id_story = data_json[\"data\"][\"reels_media\"][0][\"items\"][i][\"id\"]\n                taken_at_timestamp = data_json[\"data\"][\"reels_media\"][0][\"items\"][i][\n                    \"taken_at_timestamp\"\n                ]\n                stories_page = f\"https://www.instagram.com/stories/reel/seen\"\n\n                headers = {\n                    \"accept\": \"*/*\",\n                    \"accept-encoding\": \"gzip, deflate, br\",\n                    \"accept-language\": \"en-US,en;q=0.9\",\n                    \"content-length\": \"127\",\n                    \"content-type\": \"application/x-www-form-urlencoded\",\n                    \"cookie\": self.cookie,\n                    \"origin\": \"https://www.instagram.com\",\n                    \"referer\": f\"https://www.instagram.com/stories/{username}/{id_story}/\",\n                    \"sec-fetch-dest\": \"empty\",\n                    \"sec-fetch-mode\": \"cors\",\n                    \"sec-fetch-site\": \"same-origin\",\n                    \"user-agent\": \"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36\",\n                    \"x-csrftoken\": self.csrf_token,\n                    \"x-ig-app-id\": \"936619743392459\",\n                    \"x-ig-www-claim\": \"hmac.AR3dC7naiVtTKkwrEY0hwTO9zj4kLxfvf4Srvp3wFyoZFvZV\",\n                    \"x-instagram-ajax\": \"d3d3aea32e75\",\n                    \"x-requested-with\": \"XMLHttpRequest\",\n                }\n\n                data = {\n                    \"reelMediaId\": id_story,\n                    \"reelMediaOwnerId\": page_id,\n                    \"reelId\": page_id,\n                    \"reelMediaTakenAt\": taken_at_timestamp,\n                    \"viewSeenAt\": taken_at_timestamp,\n                }\n\n                requests.request(\n                    \"POST\", stories_page, headers=headers, data=data, proxies=self.proxy\n                )\n\n        except IndexError:\n            return 404\n\n        except KeyError:\n            return 404\n\n        return 200\n\n    def upload_post(self, image_path, caption=\"\"):\n        micro_time = int(datetime.now().timestamp())\n\n        headers = {\n            \"content-type\": \"image / jpg\",\n            \"content-length\": \"1\",\n            \"X-Entity-Name\": f\"fb_uploader_{micro_time}\",\n            \"Offset\": \"0\",\n            \"User-Agent\": \"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36\",\n            \"x-entity-length\": \"1\",\n            \"X-Instagram-Rupload-Params\": f'{{\"media_type\": 1, \"upload_id\": {micro_time}, \"upload_media_height\": 1080, \"upload_media_width\": 1080}}',\n            \"x-csrftoken\": self.csrf_token,\n            \"x-ig-app-id\": \"1217981644879628\",\n            \"cookie\": self.cookie,\n        }\n\n        upload_response = requests.post(\n            f\"https://www.instagram.com/rupload_igphoto/fb_uploader_{micro_time}\",\n            data=open(image_path, \"rb\"),\n            headers=headers,\n            proxies=self.proxy,\n        )\n\n        json_data = json.loads(upload_response.text)\n        upload_id = json_data[\"upload_id\"]\n\n        if json_data[\"status\"] == \"ok\":\n            url = \"https://www.instagram.com/create/configure/\"\n\n            payload = (\n                \"upload_id=\"\n                + upload_id\n                + \"&caption=\"\n                + caption\n                + \"&usertags=&custom_accessibility_caption=&retry_timeout=\"\n            )\n            payload = payload.encode(\"utf-8\")\n            headers = {\n                \"authority\": \"www.instagram.com\",\n                \"x-ig-www-claim\": \"hmac.AR2-43UfYbG2ZZLxh-BQ8N0rqGa-hESkcmxat2RqMAXejXE3\",\n                \"x-instagram-ajax\": \"adb961e446b7-hot\",\n                \"content-type\": \"application/x-www-form-urlencoded\",\n                \"accept\": \"*/*\",\n                \"user-agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36\",\n                \"x-requested-with\": \"XMLHttpRequest\",\n                \"x-csrftoken\": self.csrf_token,\n                \"x-ig-app-id\": \"1217981644879628\",\n                \"origin\": \"https://www.instagram.com\",\n                \"sec-fetch-site\": \"same-origin\",\n                \"sec-fetch-mode\": \"cors\",\n                \"sec-fetch-dest\": \"empty\",\n                \"referer\": \"https://www.instagram.com/create/details/\",\n                \"accept-language\": \"en-US,en;q=0.9,fa-IR;q=0.8,fa;q=0.7\",\n                \"cookie\": self.cookie,\n            }\n\n            response = requests.request(\n                \"POST\", url, headers=headers, data=payload, proxies=self.proxy\n            )\n            json_data = json.loads(response.text)\n\n            if json_data[\"status\"] == \"ok\":\n                return 200\n\n        else:\n            return 400\n\n    def upload_story(self, image_path):\n        micro_time = int(datetime.now().timestamp())\n\n        headers = {\n            \"content-type\": \"image / jpg\",\n            \"content-length\": \"1\",\n            \"X-Entity-Name\": f\"fb_uploader_{micro_time}\",\n            \"Offset\": \"0\",\n            \"User-Agent\": \"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36\",\n            \"x-entity-length\": \"1\",\n            \"X-Instagram-Rupload-Params\": f'{{\"media_type\": 1, \"upload_id\": {micro_time}, \"upload_media_height\": 1080, \"upload_media_width\": 1080}}',\n            \"x-csrftoken\": self.csrf_token,\n            \"x-ig-app-id\": \"1217981644879628\",\n            \"cookie\": self.cookie,\n        }\n\n        upload_response = requests.post(\n            f\"https://www.instagram.com/rupload_igphoto/fb_uploader_{micro_time}\",\n            data=open(image_path, \"rb\"),\n            headers=headers,\n            proxies=self.proxy,\n        )\n\n        json_data = json.loads(upload_response.text)\n        upload_id = json_data[\"upload_id\"]\n\n        if json_data[\"status\"] == \"ok\":\n            url = \"https://www.instagram.com/create/configure_to_story/\"\n\n            payload = (\n                \"upload_id=\"\n                + upload_id\n                + \"&caption=&usertags=&custom_accessibility_caption=&retry_timeout=\"\n            )\n            headers = {\n                \"authority\": \"www.instagram.com\",\n                \"x-ig-www-claim\": \"hmac.AR2-43UfYbG2ZZLxh-BQ8N0rqGa-hESkcmxat2RqMAXejXE3\",\n                \"x-instagram-ajax\": \"adb961e446b7-hot\",\n                \"content-type\": \"application/x-www-form-urlencoded\",\n                \"accept\": \"*/*\",\n                \"user-agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36\",\n                \"x-requested-with\": \"XMLHttpRequest\",\n                \"x-csrftoken\": self.csrf_token,\n                \"x-ig-app-id\": \"1217981644879628\",\n                \"origin\": \"https://www.instagram.com\",\n                \"sec-fetch-site\": \"same-origin\",\n                \"sec-fetch-mode\": \"cors\",\n                \"sec-fetch-dest\": \"empty\",\n                \"referer\": \"https://www.instagram.com/create/details/\",\n                \"accept-language\": \"en-US,en;q=0.9,fa-IR;q=0.8,fa;q=0.7\",\n                \"cookie\": self.cookie,\n            }\n\n            response = requests.request(\n                \"POST\", url, headers=headers, data=payload, proxies=self.proxy\n            )\n            json_data = json.loads(response.text)\n\n            if json_data[\"status\"] == \"ok\":\n                return 200\n\n        else:\n            return 400\n\n    def hashtag_posts(self, hashtag, limit=20):\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/graphql/query/?query_hash=9b498c08113f1e09617a1703c22b2f32&variables=%7B%22tag_name%22%3A%22{hashtag}%22%2C%22first%22%3A{limit}%7D\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        post_count = len(\n            json.loads(response)[\"data\"][\"hashtag\"][\"edge_hashtag_to_media\"][\"edges\"]\n        )\n\n        if limit > post_count:\n            limit = post_count\n\n        links = []\n        for i in range(0, limit):\n            links.append(\n                \"https://instagram.com/p/\"\n                + json.loads(response)[\"data\"][\"hashtag\"][\"edge_hashtag_to_media\"][\n                    \"edges\"\n                ][i][\"node\"][\"shortcode\"]\n            )\n\n        return links\n\n    def location_posts(self, location_url, limit=20):\n        id_location = location_url.split(\"/locations/\")[1].split(\"/\")[0]\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/graphql/query/?query_hash=36bd0f2bf5911908de389b8ceaa3be6d&variables=%7B%22id%22%3A%22{id_location}%22%2C%22first%22%3A{limit}%7D\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        post_count = len(\n            json.loads(response)[\"data\"][\"location\"][\"edge_location_to_media\"][\"edges\"]\n        )\n\n        if limit > post_count:\n            limit = post_count\n\n        links = []\n        for i in range(0, limit):\n            links.append(\n                \"https://instagram.com/p/\"\n                + json.loads(response)[\"data\"][\"location\"][\"edge_location_to_media\"][\n                    \"edges\"\n                ][i][\"node\"][\"shortcode\"]\n            )\n\n        return links\n\n    def user_posts_count(self, username):\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        post_count = json.loads(response)[\"graphql\"][\"user\"][\n            \"edge_owner_to_timeline_media\"\n        ][\"count\"]\n\n        return post_count\n\n    def user_followers_count(self, username):\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        followers_count = json.loads(response)[\"graphql\"][\"user\"][\"edge_followed_by\"][\n            \"count\"\n        ]\n\n        return followers_count\n\n    def user_follow_count(self, username):\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        follow_count = json.loads(response)[\"graphql\"][\"user\"][\"edge_follow\"][\"count\"]\n\n        return follow_count\n\n    def like_count(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        headers = self._get_headers()\n\n        if post_link[-1] == \"/\":\n            post_link = post_link[:-1]\n\n        response = self.session.get(\n            f\"{post_link}/?__a=1\", headers=headers, proxies=self.proxy\n        ).text\n        like_count = json.loads(response)[\"graphql\"][\"shortcode_media\"][\n            \"edge_media_preview_like\"\n        ][\"count\"]\n\n        return like_count\n\n    def comment_count(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        headers = self._get_headers()\n\n        if post_link[-1] == \"/\":\n            post_link = post_link[:-1]\n\n        response = self.session.get(\n            f\"{post_link}/?__a=1\", headers=headers, proxies=self.proxy\n        ).text\n        comment_count = json.loads(response)[\"graphql\"][\"shortcode_media\"][\n            \"edge_media_preview_comment\"\n        ][\"count\"]\n\n        return comment_count\n\n    def user_posts(self, username, limit=50):\n        posts_have = self.user_posts_count(username)\n\n        if posts_have < limit:\n            limit = posts_have\n\n        limit_k = limit\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        user_id = json.loads(response)[\"graphql\"][\"user\"][\"id\"]\n\n        links = []\n\n        response = self.session.get(\n            f\"https://www.instagram.com/graphql/query/?query_hash=003056d32c2554def87228bc3fd9668a&variables=%7B%22id%22%3A%22{user_id}%22%2C%22first%22%3A{limit}%7D\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        post_count = len(\n            json.loads(response)[\"data\"][\"user\"][\"edge_owner_to_timeline_media\"][\n                \"edges\"\n            ]\n        )\n\n        if limit > post_count:\n            limit = post_count\n\n        for i in range(0, limit):\n            links.append(\n                \"https://instagram.com/p/\"\n                + json.loads(response)[\"data\"][\"user\"][\"edge_owner_to_timeline_media\"][\n                    \"edges\"\n                ][i][\"node\"][\"shortcode\"]\n            )\n\n        if limit_k > 50:\n            limit = limit_k - 50\n            limit_k = limit\n            while limit_k > 0:\n                try:\n                    after = json.loads(response)[\"data\"][\"user\"][\n                        \"edge_owner_to_timeline_media\"\n                    ][\"page_info\"][\"end_cursor\"]\n                    response = self.session.get(\n                        f'https://www.instagram.com/graphql/query/?query_hash=003056d32c2554def87228bc3fd9668a&variables=%7B%22id%22%3A%22{user_id}%22%2C%22first%22%3A50%2C%22after%22%3A%22{after.replace(\"==\",\"\")}%3D%3D%22%7D',\n                        headers=headers,\n                        proxies=self.proxy,\n                    ).text\n                    post_count = len(\n                        json.loads(response)[\"data\"][\"user\"][\n                            \"edge_owner_to_timeline_media\"\n                        ][\"edges\"]\n                    )\n\n                    if limit > post_count:\n                        limit = post_count\n\n                    limit_k -= limit\n                    for i in range(0, limit):\n                        links.append(\n                            \"https://instagram.com/p/\"\n                            + json.loads(response)[\"data\"][\"user\"][\n                                \"edge_owner_to_timeline_media\"\n                            ][\"edges\"][i][\"node\"][\"shortcode\"]\n                        )\n                    limit = limit_k\n                except:\n                    break\n        return links\n\n    def user_follows(self, username, limit=49):\n        followed = self.user_follow_count(username)\n\n        if followed < limit:\n            limit = followed\n\n        limit_k = limit\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        user_id = json.loads(response)[\"graphql\"][\"user\"][\"id\"]\n\n        usernames = []\n\n        response = self.session.get(\n            f\"https://www.instagram.com/graphql/query/?query_hash=d04b0a864b4b54837c0d870b0e77e076&variables=%7B%22id%22%3A%22{user_id}%22%2C%22first%22%3A{limit}%7D\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        follow_count = len(json.loads(response)[\"data\"][\"user\"][\"edge_follow\"][\"edges\"])\n\n        if limit > follow_count:\n            limit = follow_count\n\n        for i in range(0, limit):\n            usernames.append(\n                json.loads(response)[\"data\"][\"user\"][\"edge_follow\"][\"edges\"][i][\"node\"][\n                    \"username\"\n                ]\n            )\n\n        if limit_k > 49:\n            limit = limit_k - 49\n            limit_k = limit\n            while limit_k > 0:\n                try:\n                    after = json.loads(response)[\"data\"][\"user\"][\"edge_follow\"][\n                        \"page_info\"\n                    ][\"end_cursor\"]\n                    response = self.session.get(\n                        f'https://www.instagram.com/graphql/query/?query_hash=d04b0a864b4b54837c0d870b0e77e076&variables=%7B%22id%22%3A%22{user_id}%22%2C%22first%22%3A50%2C%22after%22%3A%22{after.replace(\"==\",\"\")}%3D%3D%22%7D',\n                        headers=headers,\n                        proxies=self.proxy,\n                    ).text\n                    follow_count = len(\n                        json.loads(response)[\"data\"][\"user\"][\"edge_follow\"][\"edges\"]\n                    )\n\n                    if limit > follow_count:\n                        limit = follow_count\n\n                    limit_k -= limit\n                    for i in range(0, limit):\n                        usernames.append(\n                            json.loads(response)[\"data\"][\"user\"][\"edge_follow\"][\n                                \"edges\"\n                            ][i][\"node\"][\"username\"]\n                        )\n                    limit = limit_k\n                except:\n                    break\n        return usernames\n\n    def user_followers(self, username, limit=49):\n        follower = self.user_followers_count(username)\n\n        if follower < limit:\n            limit = follower\n\n        limit_k = limit\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        user_id = json.loads(response)[\"graphql\"][\"user\"][\"id\"]\n\n        usernames = []\n\n        response = self.session.get(\n            f\"https://www.instagram.com/graphql/query/?query_hash=c76146de99bb02f6415203be841dd25a&variables=%7B%22id%22%3A%22{user_id}%22%2C%22first%22%3A{limit}%7D\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        follower_count = len(\n            json.loads(response)[\"data\"][\"user\"][\"edge_followed_by\"][\"edges\"]\n        )\n\n        if limit > follower_count:\n            limit = follower_count\n\n        for i in range(0, limit):\n            usernames.append(\n                json.loads(response)[\"data\"][\"user\"][\"edge_followed_by\"][\"edges\"][i][\n                    \"node\"\n                ][\"username\"]\n            )\n\n        if limit_k > 49:\n            limit = limit_k - 49\n            limit_k = limit\n            while limit_k > 0:\n                try:\n                    after = json.loads(response)[\"data\"][\"user\"][\"edge_followed_by\"][\n                        \"page_info\"\n                    ][\"end_cursor\"]\n                    response = self.session.get(\n                        f'https://www.instagram.com/graphql/query/?query_hash=c76146de99bb02f6415203be841dd25a&variables=%7B%22id%22%3A%22{user_id}%22%2C%22first%22%3A50%2C%22after%22%3A%22{after.replace(\"==\",\"\")}%3D%3D%22%7D',\n                        headers=headers,\n                        proxies=self.proxy,\n                    ).text\n                    follower_count = len(\n                        json.loads(response)[\"data\"][\"user\"][\"edge_followed_by\"][\n                            \"edges\"\n                        ]\n                    )\n\n                    if limit > follower_count:\n                        limit = follower_count\n\n                    limit_k -= limit\n                    for i in range(0, limit):\n                        usernames.append(\n                            json.loads(response)[\"data\"][\"user\"][\"edge_followed_by\"][\n                                \"edges\"\n                            ][i][\"node\"][\"username\"]\n                        )\n                    limit = limit_k\n                except:\n                    break\n        return usernames\n\n    def post_likers(self, post_link, limit=50):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        likers = self.like_count(post_link)\n\n        if likers < limit:\n            limit = likers\n\n        limit_k = limit\n        headers = self._get_headers()\n\n        shortcode = post_link.split(\"/p/\")[1].replace(\"/\", \"\")\n        usernames = []\n\n        response = self.session.get(\n            f\"https://www.instagram.com/graphql/query/?query_hash=d5d763b1e2acf209d62d22d184488e57&variables=%7B%22shortcode%22%3A%22{shortcode}%22%2C%22first%22%3A{limit}%7D\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        like_count = len(\n            json.loads(response)[\"data\"][\"shortcode_media\"][\"edge_liked_by\"][\"edges\"]\n        )\n\n        if limit > like_count:\n            limit = like_count\n\n        for i in range(0, limit):\n            usernames.append(\n                json.loads(response)[\"data\"][\"shortcode_media\"][\"edge_liked_by\"][\n                    \"edges\"\n                ][i][\"node\"][\"username\"]\n            )\n\n        if limit_k > 50:\n            limit = limit_k - 50\n            limit_k = limit\n            while limit_k > 0:\n                try:\n                    after = json.loads(response)[\"data\"][\"shortcode_media\"][\n                        \"edge_liked_by\"\n                    ][\"page_info\"][\"end_cursor\"]\n                    response = self.session.get(\n                        f'https://www.instagram.com/graphql/query/?query_hash=d5d763b1e2acf209d62d22d184488e57&variables=%7B%22shortcode%22%3A%22{shortcode}%22%2C%22first%22%3A50%2C%22after%22%3A%22{after.replace(\"==\",\"\")}%3D%3D%22%7D',\n                        headers=headers,\n                        proxies=self.proxy,\n                    ).text\n                    like_count = len(\n                        json.loads(response)[\"data\"][\"shortcode_media\"][\n                            \"edge_liked_by\"\n                        ][\"edges\"]\n                    )\n\n                    if limit > like_count:\n                        limit = like_count\n\n                    limit_k -= limit\n                    for i in range(0, limit):\n                        usernames.append(\n                            json.loads(response)[\"data\"][\"shortcode_media\"][\n                                \"edge_liked_by\"\n                            ][\"edges\"][i][\"node\"][\"username\"]\n                        )\n                    limit = limit_k\n                except:\n                    break\n        return usernames\n\n    def post_commenters(self, post_link, limit=50):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        commenters = self.comment_count(post_link)\n\n        if commenters < limit:\n            limit = commenters\n\n        limit_k = limit\n        headers = self._get_headers()\n\n        shortcode = post_link.split(\"/p/\")[1].replace(\"/\", \"\")\n\n        usernames = []\n\n        response = self.session.get(\n            f\"https://www.instagram.com/graphql/query/?query_hash=bc3296d1ce80a24b1b6e40b1e72903f5&variables=%7B%22shortcode%22%3A%22{shortcode}%22%2C%22first%22%3A{limit}%7D\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        comment_count = len(\n            json.loads(response)[\"data\"][\"shortcode_media\"][\n                \"edge_media_to_parent_comment\"\n            ][\"edges\"]\n        )\n\n        if limit > comment_count:\n            limit = comment_count\n\n        for i in range(0, limit):\n            usernames.append(\n                json.loads(response)[\"data\"][\"shortcode_media\"][\n                    \"edge_media_to_parent_comment\"\n                ][\"edges\"][i][\"node\"][\"owner\"][\"username\"]\n            )\n\n        if limit_k > 50:\n            limit = limit_k - 50\n            limit_k = limit\n            while limit_k > 0:\n                try:\n                    response = self.session.get(\n                        \"https://www.instagram.com/graphql/query/?query_hash=bc3296d1ce80a24b1b6e40b1e72903f5&variables={%22shortcode%22:%22\"\n                        + shortcode\n                        + \"%22,%22first%22:50,%22after%22:\"\n                        + json.dumps(\n                            json.loads(response)[\"data\"][\"shortcode_media\"][\n                                \"edge_media_to_parent_comment\"\n                            ][\"page_info\"][\"end_cursor\"]\n                        )\n                        + \"}\",\n                        headers=headers,\n                        proxies=self.proxy,\n                    ).text\n                    comment_count = len(\n                        json.loads(response)[\"data\"][\"shortcode_media\"][\n                            \"edge_media_to_parent_comment\"\n                        ][\"edges\"]\n                    )\n\n                    if limit > comment_count:\n                        limit = comment_count\n\n                    limit_k -= limit\n                    for i in range(0, limit):\n                        usernames.append(\n                            json.loads(response)[\"data\"][\"shortcode_media\"][\n                                \"edge_media_to_parent_comment\"\n                            ][\"edges\"][i][\"node\"][\"owner\"][\"username\"]\n                        )\n                    limit = limit_k\n                except:\n                    break\n        return usernames\n\n    def feed_posts(self):\n        headers = self._get_headers()\n        response = self.session.get(\n            \"https://www.instagram.com/graphql/query/?query_hash=c699b185975935ae2a457f24075de8c7\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n\n        post_count = len(\n            json.loads(response)[\"data\"][\"user\"][\"edge_web_feed_timeline\"][\"edges\"]\n        )\n        feed_posts = []\n        for i in range(0, post_count):\n            feed_posts.append(\n                \"https://instagram.com/p/\"\n                + json.loads(response)[\"data\"][\"user\"][\"edge_web_feed_timeline\"][\n                    \"edges\"\n                ][i][\"node\"][\"shortcode\"]\n            )\n\n        return feed_posts\n\n    def post_owner(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        headers = self._get_headers()\n\n        if post_link[-1] == \"/\":\n            post_link = post_link[:-1]\n\n        response = self.session.get(\n            f\"{post_link}/?__a=1\", headers=headers, proxies=self.proxy\n        ).text\n        owner = json.loads(response)[\"graphql\"][\"shortcode_media\"][\"owner\"][\"username\"]\n\n        return owner\n\n    def post_caption(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except Exception:\n            pass\n        headers = self._get_headers()\n\n        if post_link[-1] == \"/\":\n            post_link = post_link[:-1]\n\n        response = self.session.get(\n            f\"{post_link}/?__a=1\", headers=headers, proxies=self.proxy\n        ).text\n        caption = json.loads(response)[\"graphql\"][\"shortcode_media\"][\n            \"edge_media_to_caption\"\n        ][\"edges\"][0][\"node\"][\"text\"]\n\n        return caption\n\n    def post_location(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        headers = self._get_headers()\n\n        if post_link[-1] == \"/\":\n            post_link = post_link[:-1]\n\n        response = self.session.get(\n            f\"{post_link}/?__a=1\", headers=headers, proxies=self.proxy\n        ).text\n        location = {\n            \"id\": json.loads(response)[\"graphql\"][\"shortcode_media\"][\"location\"][\"id\"],\n            \"name\": json.loads(response)[\"graphql\"][\"shortcode_media\"][\"location\"][\n                \"name\"\n            ],\n        }\n\n        return location\n\n    def post_hashtags(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        hashtag_filter = self.post_caption(post_link).replace(\"\\n\", \" \").split()\n        hashtags = []\n        for hashtag in hashtag_filter:\n            if hashtag.startswith(\"#\"):\n                hashtags.append(hashtag)\n\n        return hashtags\n\n    def post_tagged_user(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        headers = self._get_headers()\n\n        if post_link[-1] == \"/\":\n            post_link = post_link[:-1]\n\n        tagged_users = []\n        try:\n            response = self.session.get(\n                f\"{post_link}/?__a=1\", headers=headers, proxies=self.proxy\n            ).text\n            tag_count = len(\n                json.loads(response)[\"graphql\"][\"shortcode_media\"][\n                    \"edge_sidecar_to_children\"\n                ][\"edges\"][0][\"node\"][\"edge_media_to_tagged_user\"][\"edges\"]\n            )\n\n            for i in range(0, tag_count):\n                tagged_users.append(\n                    json.loads(response)[\"graphql\"][\"shortcode_media\"][\n                        \"edge_sidecar_to_children\"\n                    ][\"edges\"][0][\"node\"][\"edge_media_to_tagged_user\"][\"edges\"][i][\n                        \"node\"\n                    ][\n                        \"user\"\n                    ][\n                        \"username\"\n                    ]\n                )\n        except:\n            try:\n                response = self.session.get(\n                    f\"{post_link}/?__a=1\", headers=headers, proxies=self.proxy\n                ).text\n                tag_count = len(\n                    json.loads(response)[\"graphql\"][\"shortcode_media\"][\n                        \"edge_media_to_tagged_user\"\n                    ][\"edges\"]\n                )\n\n                for i in range(0, tag_count):\n                    tagged_users.append(\n                        json.loads(response)[\"graphql\"][\"shortcode_media\"][\n                            \"edge_media_to_tagged_user\"\n                        ][\"edges\"][i][\"node\"][\"user\"][\"username\"]\n                    )\n            except:\n                pass\n\n        return tagged_users\n\n    def post_time(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        headers = self._get_headers()\n\n        if post_link[-1] == \"/\":\n            post_link = post_link[:-1]\n\n        response = self.session.get(\n            f\"{post_link}/?__a=1\", headers=headers, proxies=self.proxy\n        ).text\n        time = {\n            \"timestamp\": json.loads(response)[\"graphql\"][\"shortcode_media\"][\n                \"taken_at_timestamp\"\n            ],\n            \"datetime\": str(\n                datetime.fromtimestamp(\n                    json.loads(response)[\"graphql\"][\"shortcode_media\"][\n                        \"taken_at_timestamp\"\n                    ]\n                )\n            ),\n        }\n\n        return time\n\n    def post_type(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        headers = self._get_headers()\n\n        if post_link[-1] == \"/\":\n            post_link = post_link[:-1]\n\n        response = self.session.get(\n            f\"{post_link}/?__a=1\", headers=headers, proxies=self.proxy\n        ).text\n        if bool(json.loads(response)[\"graphql\"][\"shortcode_media\"][\"is_video\"]):\n            post_type = \"video\"\n        else:\n            post_type = \"picture\"\n\n        return post_type\n\n    def video_views_count(self, post_link):\n        if post_link.find(\"/tv/\") != -1:\n            post_link = post_link.replace(\"/tv/\", \"/p/\")\n        try:\n            post_link = post_link.replace(post_link.split(\"/p/\")[1].split(\"/\")[1], \"\")\n        except:\n            pass\n        if self.post_type(post_link) == \"video\":\n            headers = self._get_headers()\n\n            if post_link[-1] == \"/\":\n                post_link = post_link[:-1]\n\n            response = self.session.get(\n                f\"{post_link}/?__a=1\", headers=headers, proxies=self.proxy\n            ).text\n            view_count = json.loads(response)[\"graphql\"][\"shortcode_media\"][\n                \"video_view_count\"\n            ]\n\n            return view_count\n\n    def followed_by_me(self, username):\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        followed_by_viewer = bool(\n            json.loads(response)[\"graphql\"][\"user\"][\"followed_by_viewer\"]\n        )\n\n        return followed_by_viewer\n\n    def follows_me(self, username):\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        follows_viewer = bool(json.loads(response)[\"graphql\"][\"user\"][\"follows_viewer\"])\n\n        return follows_viewer\n\n    def user_external_url(self, username):\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        url = json.loads(response)[\"graphql\"][\"user\"][\"external_url\"]\n\n        return url\n\n    def verified_user(self, username):\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        is_verified = bool(json.loads(response)[\"graphql\"][\"user\"][\"is_verified\"])\n\n        return is_verified\n\n    def private_user(self, username):\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        is_private = bool(json.loads(response)[\"graphql\"][\"user\"][\"is_private\"])\n\n        return is_private\n\n    def user_bio(self, username):\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        bio = json.loads(response)[\"graphql\"][\"user\"][\"biography\"]\n\n        return bio\n\n    def user_dp(self, username):\n        headers = self._get_headers()\n\n        response = self.session.get(\n            f\"https://www.instagram.com/{username}/?__a=1\",\n            headers=headers,\n            proxies=self.proxy,\n        ).text\n        dp_url = json.loads(response)[\"graphql\"][\"user\"][\"profile_pic_url_hd\"]\n\n        return dp_url\n\n    def _get_headers(self, options=None):\n        if options is None:\n            options = dict()\n\n        headers = {\n            \"accept\": \"*/*\",\n            \"accept-encoding\": \"gzip, deflate, br\",\n            \"accept-language\": \"en-US,en;q=0.9\",\n            \"content-length\": \"0\",\n            \"content-type\": \"application/x-www-form-urlencoded\",\n            \"cookie\": self.cookie,\n            \"sec-fetch-dest\": \"empty\",\n            \"sec-fetch-mode\": \"cors\",\n            \"sec-fetch-site\": \"same-origin\",\n            \"user-agent\": \"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36\",\n            \"x-csrftoken\": self.csrf_token,\n            \"x-ig-app-id\": \"936619743392459\",\n            \"x-ig-www-claim\": \"hmac.AR3dC7naiVtTKkwrEY0hwTO9zj4kLxfvf4Srvp3wFyoZFqSx\",\n            \"x-instagram-ajax\": \"d3d3aea32e75\",\n            \"x-requested-with\": \"XMLHttpRequest\",\n        }\n\n        for key, value in options.items():\n            headers[key] = value\n\n        return headers\n"
  },
  {
    "path": "bhagavad_gita_api/SocialBot.py",
    "content": "import os\n\nimport tweepy\nfrom PIL import Image, ImageDraw, ImageFont\nfrom textwrap3 import wrap\n\nfrom bhagavad_gita_api.config import settings\nfrom bhagavad_gita_api.models import gita as models\nfrom bhagavad_gita_api.MyIGBot import MyIGBot\n\n\nclass SocialBot:\n    sanskrit_text: str\n    translation_hindi: str\n    translation_english: str\n    image_path: str = \"bhagavad_gita_api/media/images/output.jpg\"\n\n    def __init__(self, verse, translations):\n        self.translation_english = (\n            translations.filter(models.GitaTranslation.author_name == \"Swami Sivananda\")\n            .first()\n            .description\n        ).replace(\"\\n\", \" \")\n\n        self.translation_hindi = (\n            translations.filter(\n                models.GitaTranslation.author_name == \"Swami Ramsukhdas\"\n            )\n            .first()\n            .description\n        ).replace(\"\\n\", \" \")\n\n        self.sanskrit_text = verse.text.replace(\"\\n\", \" \")\n        self.create_image_post(text=self.translation_english)\n\n    def create_image_post(self, text):\n\n        \"\"\"\n        using pillow to add text on an image template, adjusting font\n        size and line width to avoid overflows\n        \"\"\"\n        img = Image.open(\"bhagavad_gita_api/media/images/template.jpg\")\n        draw = ImageDraw.Draw(img)\n        font_size = 40\n        font = ImageFont.truetype(\n            \"bhagavad_gita_api/media/helveticaneue.ttf\", font_size\n        )\n\n        lines = wrap(text=text, width=50)\n\n        line_width, line_height = font.getsize(lines[0])\n\n        text_height = len(lines) * line_height\n\n        while text_height > 250:\n            print(\"in the loop\")\n            font_size -= 5\n            font = ImageFont.truetype(\n                \"bhagavad_gita_api/media/helveticaneue.ttf\", font_size\n            )\n            line_height -= 10\n            text_height = len(lines) * line_height\n\n        y_text = 805\n\n        image_width, image_height = img.size\n\n        for line in lines:\n            line_width, line_height = font.getsize(line)\n            draw.text(\n                ((image_width - line_width) / 2, y_text),\n                line,\n                font=font,\n                fill=(0, 0, 0),\n            )\n            y_text += line_height\n        rgb_im = img.convert(\"RGB\")\n        rgb_im.save(\"bhagavad_gita_api/media/images/output.jpg\")\n        print(\"image created\")\n\n    def post_on_twitter(self):\n        auth = tweepy.OAuthHandler(\n            settings.TWITTER[\"CONSUMER_KEY\"], settings.TWITTER[\"CONSUMER_SECRET\"]\n        )\n        auth.set_access_token(\n            settings.TWITTER[\"ACCESS_TOKEN\"], settings.TWITTER[\"ACCESS_TOKEN_SECRET\"]\n        )\n        api = tweepy.API(auth)\n        media = api.media_upload(\"bhagavad_gita_api/media/images/output.jpg\")\n        try:\n            tweet_text = \"Glories To Shri Hari\"\n            post_result = api.update_status(\n                status=tweet_text, media_ids=[media.media_id_string]\n            )\n\n            tweet_text = \"Sanskrit Text : \" + self.sanskrit_text\n            sanskrit_text = api.update_status(\n                status=tweet_text,\n                in_reply_to_status_id=post_result.id,\n                auto_populate_reply_metadata=True,\n            )\n\n            tweet_text = \"Hindi Translation : \" + self.translation_hindi\n            hindi_text = api.update_status(\n                status=tweet_text,\n                in_reply_to_status_id=sanskrit_text.id,\n                auto_populate_reply_metadata=True,\n            )\n            print(hindi_text)\n            return 200\n\n        except Exception as e:\n            return e\n\n    def post_on_instagram(self):\n\n        # remove cookie if exists, package throws error on expired cookie\n        if os.path.exists(\"cookie_iiradhakrishnaii.bot\"):\n            os.remove(\"cookie_iiradhakrishnaii.bot\")\n        else:\n            pass\n\n        try:\n            caption = f\"\"\"\n            Glories To Shri Hari \\n\n            Sanskrit text : {self.sanskrit_text} \\n\n            Hindi translation: {self.translation_hindi}\\n\n            \"\"\"\n            bot = MyIGBot(\n                settings.INSTAGRAM[\"USERNAME\"], settings.INSTAGRAM[\"PASSWORD\"]\n            )\n            response = bot.upload_post(\n                \"bhagavad_gita_api/media/images/output.jpg\", caption=caption\n            )\n            print(response)  # if the response code is 200 that means ok\n\n            return 200\n        except Exception:\n            return 500\n"
  },
  {
    "path": "bhagavad_gita_api/__init__.py",
    "content": "\"\"\"Package bhagavad-gita-api.\n\nBhagavad Gita API allows any developer to use content from Bhagavad Gita in their applications.\n\nMIT License\n\nCopyright (c) 2021 The Gita Initiative <contact@bhagavadgita.io>\n\nhttps://github.com/gita/bhagavad-gita-api\n\"\"\"\n\nfrom importlib.metadata import version\n\n__version__ = version(__package__)\n"
  },
  {
    "path": "bhagavad_gita_api/api/__init__.py",
    "content": ""
  },
  {
    "path": "bhagavad_gita_api/api/api_v2/__init__.py",
    "content": ""
  },
  {
    "path": "bhagavad_gita_api/api/api_v2/api.py",
    "content": "from fastapi import APIRouter\n\nfrom bhagavad_gita_api.api.api_v2.endpoints import gita, social\n\napi_router = APIRouter()\napi_router.include_router(gita.router)\napi_router.include_router(social.router, include_in_schema=True)\n"
  },
  {
    "path": "bhagavad_gita_api/api/api_v2/endpoints/__init__.py",
    "content": ""
  },
  {
    "path": "bhagavad_gita_api/api/api_v2/endpoints/gita.py",
    "content": "import logging\nimport random\nfrom datetime import date\nfrom typing import List\n\nfrom fastapi import APIRouter, Depends, HTTPException, Response\nfrom sqlalchemy import func, or_\nfrom sqlalchemy.orm import Session, joinedload\n\nfrom bhagavad_gita_api.api import deps\nfrom bhagavad_gita_api.models import gita as models\nfrom bhagavad_gita_api.models import schemas\n\nlogger = logging.getLogger(\"api\")\nlogger.setLevel(logging.DEBUG)\n\nrouter = APIRouter()\n\n\n@router.get(\"/chapters/\", response_model=List[schemas.GitaChapter], tags=[\"chapters\"])\nasync def get_all_chapters(\n    skip: int = 0,\n    limit: int = 18,\n    db: Session = Depends(deps.get_db),\n):\n    chapters = (\n        db.query(models.GitaChapter)\n        .with_entities(\n            models.GitaChapter.id,\n            models.GitaChapter.slug,\n            models.GitaChapter.name,\n            models.GitaChapter.name_transliterated,\n            models.GitaChapter.name_translated,\n            models.GitaChapter.verses_count,\n            models.GitaChapter.chapter_number,\n            models.GitaChapter.name_meaning,\n            models.GitaChapter.chapter_summary,\n            models.GitaChapter.chapter_summary_hindi,\n        )\n        .order_by(models.GitaChapter.id.asc())\n        .offset(skip)\n        .limit(limit)\n        .all()\n    )\n    return chapters\n\n\n@router.get(\n    \"/chapters/{chapter_number}/\", response_model=schemas.GitaChapter, tags=[\"chapters\"]\n)\nasync def get_particular_chapter(\n    chapter_number: int, db: Session = Depends(deps.get_db)\n):\n    chapter = (\n        db.query(models.GitaChapter)\n        .filter(models.GitaChapter.chapter_number == chapter_number)\n        .with_entities(\n            models.GitaChapter.id,\n            models.GitaChapter.slug,\n            models.GitaChapter.name,\n            models.GitaChapter.name_transliterated,\n            models.GitaChapter.name_translated,\n            models.GitaChapter.verses_count,\n            models.GitaChapter.chapter_number,\n            models.GitaChapter.name_meaning,\n            models.GitaChapter.chapter_summary,\n            models.GitaChapter.chapter_summary_hindi,\n        )\n        .first()\n    )\n    if chapter is None:\n        raise HTTPException(status_code=404, detail=\"Chapter not found\")\n    return chapter\n\n\n# @router.get(\"/verses/\", response_model=List[schemas.GitaVerse], tags=[\"verses\"])\n# def get_all_verses_from_all_chapters(\n#     skip: int = 0, limit: int = 10, db: Session = Depends(deps.get_db)\n# ):\n#     verses = (\n#         db.query(models.GitaVerse)\n#         .options(\n#             joinedload(models.GitaVerse.commentaries),\n#             joinedload(models.GitaVerse.translations),\n#         )\n#         .order_by(models.GitaVerse.id.asc())\n#         .offset(skip)\n#         .limit(limit)\n#         .all()\n#     )\n#     return verses\n\n\n@router.get(\n    \"/chapters/{chapter_number}/verses/\",\n    response_model=List[schemas.GitaVerse],\n    tags=[\"verses\"],\n)\nasync def get_all_verses_from_particular_chapter(\n    chapter_number: int, db: Session = Depends(deps.get_db)\n):\n    verses = (\n        db.query(models.GitaVerse)\n        .options(\n            joinedload(models.GitaVerse.commentaries),\n            joinedload(models.GitaVerse.translations),\n        )\n        .order_by(models.GitaVerse.id.asc())\n        .filter(models.GitaVerse.chapter_number == chapter_number)\n        .all()\n    )\n    if verses is None:\n        raise HTTPException(status_code=404, detail=\"Verse not found\")\n    return verses\n\n\n@router.get(\n    \"/chapters/{chapter_number}/verses/{verse_number}/\",\n    response_model=schemas.GitaVerse,\n    tags=[\"verses\"],\n)\nasync def get_particular_verse_from_chapter(\n    chapter_number: int, verse_number: int, db: Session = Depends(deps.get_db)\n):\n    verse = (\n        db.query(models.GitaVerse)\n        .options(\n            joinedload(models.GitaVerse.commentaries),\n            joinedload(models.GitaVerse.translations),\n        )\n        .filter(\n            models.GitaVerse.chapter_number == chapter_number,\n            models.GitaVerse.verse_number == verse_number,\n        )\n        .first()\n    )\n    if verse is None:\n        raise HTTPException(status_code=404, detail=\"Verse not found\")\n    return verse\n\n\n@router.post(\"/set-daily-verse/\", tags=[\"verses\"])\nasync def set_daily_verse(db: Session = Depends(deps.get_db)):\n\n    verse_order = random.randint(1, 700)\n\n    verse = (\n        db.query(models.VerseOfDay)\n        .filter(\n            models.VerseOfDay.date == date.today(),\n        )\n        .first()\n    )\n\n    if verse is None:\n        verse_of_day = models.VerseOfDay(verse_order=verse_order, date=date.today())\n        db.add(verse_of_day)\n        db.commit()\n\n        return Response(status_code=201, content=\"Verse of the day has been set.\")\n\n    else:\n        return Response(\n            status_code=200, content=\"Verse of the day has already been set.\"\n        )\n\n\n@router.get(\n    \"/get-daily-verse/\",\n    response_model=schemas.GitaVerse,\n    tags=[\"verses\"],\n)\nasync def get_daily_verse(db: Session = Depends(deps.get_db)):\n    verse_of_day = (\n        db.query(models.VerseOfDay)\n        .filter(\n            models.VerseOfDay.date == date.today(),\n        )\n        .first()\n    )\n\n    if verse_of_day:\n        verse = (\n            db.query(models.GitaVerse)\n            .options(\n                joinedload(models.GitaVerse.commentaries),\n                joinedload(models.GitaVerse.translations),\n            )\n            .filter(models.GitaVerse.id == verse_of_day.verse_order)\n            .first()\n        )\n\n        if verse:\n            print(verse)\n            return verse\n\n    raise HTTPException(status_code=404, detail=\"Verse of the day not found.\")\n\n\n@router.get(\"/search\", response_model=List[schemas.GitaVerseBase], tags=[\"search\"])\ndef search_gita(query: str, db: Session = Depends(deps.get_db)):\n    res = (\n        db.query(models.GitaVerse)\n        .filter(\n            or_(\n                models.GitaVerse.transliteration.op(\"@@\")(func.plainto_tsquery(query)),\n                models.GitaVerse.word_meanings.op(\"@@\")(func.plainto_tsquery(query)),\n            )\n        )\n        .all()\n    )\n    res += (\n        db.query(models.GitaVerse)\n        .join(models.GitaTranslation)\n        .filter(\n            or_(\n                models.GitaTranslation.author_name == \"Swami Sivananda\",\n                models.GitaTranslation.author_name == \"Dr. S. Sankaranarayan\",\n                models.GitaTranslation.author_name == \"Shri Purohit Swami\",\n            )\n        )\n        .filter(\n            models.GitaTranslation.description.op(\"@@\")(func.plainto_tsquery(query))\n        )\n        .all()\n    )\n    return set(res)\n"
  },
  {
    "path": "bhagavad_gita_api/api/api_v2/endpoints/social.py",
    "content": "import logging\nfrom datetime import date\n\nfrom fastapi import APIRouter, Depends, HTTPException, Response\nfrom sqlalchemy.orm import Session\n\nfrom bhagavad_gita_api.api import deps\nfrom bhagavad_gita_api.models import gita as models\n\n# from bhagavad_gita_api.utils import post_on_instagram,post_on_twitter\nfrom bhagavad_gita_api.SocialBot import SocialBot\n\nlogger = logging.getLogger(\"api\")\nlogger.setLevel(logging.DEBUG)\n\nrouter = APIRouter()\n\n\n@router.post(\"/post_verse_of_the_day/\", tags=[\"social\"])\nasync def post_instagram(db: Session = Depends(deps.get_db)):\n    verse_of_day = (\n        db.query(models.VerseOfDay)\n        .filter(\n            models.VerseOfDay.date == date.today(),\n        )\n        .first()\n    )\n\n    if verse_of_day:\n        verse = (\n            db.query(models.GitaVerse)\n            .join(models.GitaTranslation)\n            .filter(models.GitaVerse.id == verse_of_day.verse_order)\n            .first()\n        )\n\n        if verse:\n\n            # CALL INSTAGRAM POSTING FUNCTION HERE\n            translations = db.query(models.GitaTranslation).filter(\n                models.GitaTranslation.verse_id == verse.id\n            )\n            bot = SocialBot(verse, translations)\n            twitter_response = bot.post_on_twitter()\n            # instagram_response = bot.post_on_instagram()\n\n            if twitter_response == 200:\n                return Response(\n                    status_code=201,\n                    content=\"Verse of the day has been posted on twitter\",\n                )\n            else:\n                HTTPException(\n                    status_code=500, detail=\"internal server error in posting \"\n                )\n\n    raise HTTPException(status_code=404, detail=\"Verse of the day not found.\")\n"
  },
  {
    "path": "bhagavad_gita_api/api/deps.py",
    "content": "from typing import Generator\n\nfrom fastapi import Depends, HTTPException, Security, status\nfrom fastapi.security.api_key import APIKeyHeader\nfrom sqlalchemy.orm import Session\n\nfrom bhagavad_gita_api import crud\nfrom bhagavad_gita_api.db.session import SessionLocal\nfrom bhagavad_gita_api.models.user import User\n\nAPI_KEY_NAME = \"X-API-KEY\"\napi_key_header_auth = APIKeyHeader(name=API_KEY_NAME, auto_error=True)\n\n\ndef get_db() -> Generator:\n    try:\n        db = SessionLocal()\n        yield db\n    finally:\n        db.close()\n\n\ndef get_current_user(\n    db: Session = Depends(get_db), api_key_header: str = Security(api_key_header_auth)\n) -> User:\n    if api_key_header not in crud.get_valid_api_keys(db):\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Invalid API Key\",\n        )\n    user = crud.get_user_by_api_key(db, api_key=api_key_header)\n    if not user:\n        raise HTTPException(status_code=404, detail=\"Account not found.\")\n    return user\n\n\ndef get_current_active_user(\n    current_user: User = Depends(get_current_user),\n) -> User:\n    if not current_user.is_active:\n        raise HTTPException(status_code=400, detail=\"Inactive account.\")\n    return current_user\n"
  },
  {
    "path": "bhagavad_gita_api/cli.py",
    "content": "import typer\n\nfrom bhagavad_gita_api.db.base_class import Base\nfrom bhagavad_gita_api.db.init_db import init_db\nfrom bhagavad_gita_api.db.session import SessionLocal, engine\n\napp = typer.Typer()\n\n\n@app.command()\ndef delete_all_data():\n    \"\"\"\n    deletes all data\n    \"\"\"\n    response = typer.prompt(\"Are you sure you want to delete all the data? [y/n]\")\n    if response == \"y\":\n        typer.echo(\"Deleting...\")\n        Base.metadata.drop_all(bind=engine)\n        typer.echo(\"Deleted.\")\n\n\n@app.command()\ndef seed_data():\n    \"\"\"\n    seeds data to database\n    \"\"\"\n    typer.echo(\"Creating initial data\")\n    db = SessionLocal()\n    init_db(db)\n    typer.echo(\"Initial data created\")\n\n\nif __name__ == \"__main__\":\n    app()\n"
  },
  {
    "path": "bhagavad_gita_api/config.py",
    "content": "import os\nfrom typing import Optional\n\nfrom dotenv import load_dotenv\nfrom pydantic import AnyUrl, BaseSettings\n\nload_dotenv()\n\n\ndef get_database_uri():\n    DB_USER = os.getenv(\"POSTGRES_USER\")\n    DB_PASS = os.getenv(\"POSTGRES_PASSWORD\")\n    DB_NAME = os.getenv(\"POSTGRES_DB\")\n    DB_HOST = os.getenv(\"DB_HOST\")\n    DB_PORT = os.getenv(\"DB_PORT\")\n    if None in [DB_USER, DB_PASS, DB_NAME, DB_HOST, DB_PORT]:\n        return None\n    return \"postgresql://{user}:{password}@{host}:{port}/{database}\".format(\n        user=DB_USER, password=DB_PASS, host=DB_HOST, port=DB_PORT, database=DB_NAME\n    )\n\n\nclass SqlDsn(AnyUrl):\n    allowed_schemes = {\"postgres\", \"postgresql\", \"sqlite\", \"mysql\"}\n\n\nclass Settings(BaseSettings):\n    project_name: str = \"Bhagavad Gita API\"\n    admin_email: str = \"admin@bhagavadgita.io\"\n    debug: bool = False\n\n    # Server\n    server_name: Optional[str]\n    server_host: Optional[str]\n    sentry_dsn: Optional[str]\n    secret_key: bytes = os.urandom(32)\n\n    API_V2_STR: str = \"/v2\"\n\n    SQLALCHEMY_DATABASE_URI: Optional[SqlDsn] = get_database_uri()\n\n    TESTER_API_KEY: str\n    # celery cronjobs\n    CELERY_BROKER: str = os.getenv(\"CELERY_BROKER\")\n    CELERY_BACKEND: str = os.getenv(\"CELERY_BACKEND\")\n    CRONJOB_BASE_URL: str = os.getenv(\"CRONJOB_BASE_URL\", \"http://api:8081\")\n\n    TWITTER = {\n        \"CONSUMER_KEY\": os.getenv(\"CONSUMER_KEY\"),\n        \"CONSUMER_SECRET\": os.getenv(\"CONSUMER_SECRET\"),\n        \"CLIENT_ID\": os.getenv(\"CLIENT_ID\"),\n        \"CLIENT_SECRET\": os.getenv(\"CLIENT_SECRET\"),\n        \"ACCESS_TOKEN\": os.getenv(\"ACCESS_TOKEN\"),\n        \"ACCESS_TOKEN_SECRET\": os.getenv(\"ACCESS_TOKEN_SECRET\"),\n    }\n\n    INSTAGRAM = {\n        \"USERNAME\": os.getenv(\"INSTAGRAM_USERNAME\"),\n        \"PASSWORD\": os.getenv(\"INSTAGRAM_PASSWORD\"),\n    }\n\n    class Config:\n        env_file = \".env\"\n\n\nsettings = Settings()\n\nif not settings.SQLALCHEMY_DATABASE_URI:\n    print(\n        \"No SQLALCHEMY_DATABASE_URI found. \\\n        \\nUsing default set Sqlite database gita.db. This is not good for running in production!\"\n    )\n    settings.SQLALCHEMY_DATABASE_URI = \"sqlite:///{}?{}\".format(\n        os.path.join(os.path.dirname(os.path.realpath(__file__)), \"gita.db\"),\n        \"check_same_thread=False\",\n    )\n"
  },
  {
    "path": "bhagavad_gita_api/cronjobs/__init__.py",
    "content": ""
  },
  {
    "path": "bhagavad_gita_api/cronjobs/celery.py",
    "content": "import requests\nfrom celery import Celery\nfrom celery.schedules import crontab\n\nfrom bhagavad_gita_api.config import settings\n\napp = Celery(\n    \"cronjobs\",\n    broker=settings.CELERY_BROKER,\n    backend=settings.CELERY_BACKEND,\n)\napp.conf.timezone = \"Asia/Calcutta\"\n\n\n@app.task\ndef set_verse():\n    url = \"{}/v2/set-daily-verse/\".format(settings.CRONJOB_BASE_URL)\n    data = {\n        \"accept\": \"application/json\",\n        \"X-API-KEY\": settings.TESTER_API_KEY,\n    }\n    r = requests.post(url=url, data=data, headers=data)\n    print(r)\n\n\napp.conf.beat_schedule = {\n    \"setup-verse-everyday\": {\n        \"task\": \"bhagavad_gita_api.cronjobs.celery.set_verse\",\n        \"schedule\": crontab(hour=0, minute=0),\n    },\n}\n\n\nif __name__ == \"__main__\":\n    app.start()\n"
  },
  {
    "path": "bhagavad_gita_api/crud.py",
    "content": "from sqlalchemy.orm import Session\n\nfrom bhagavad_gita_api.models.user import User\n\n\ndef get_user(db: Session, user_id: int):\n    return db.query(User).filter(User.id == user_id).first()\n\n\ndef get_user_by_api_key(db: Session, api_key: str):\n    return db.query(User).filter(User.api_key == api_key).first()\n\n\ndef get_valid_api_keys(db: Session):\n    valid_api_keys = [\n        u.api_key for u in db.query(User.api_key).filter(User.is_active == True).all()\n    ]\n    return valid_api_keys\n"
  },
  {
    "path": "bhagavad_gita_api/data/__init__.py",
    "content": "\"\"\"\n    Load initial data into database.\n\n   isort:skip_file\n\"\"\"\nimport os\n\n\ndef insert_all():\n    \"\"\"Insert data from github.com/gita/gita into database.\"\"\"\n\n    from bhagavad_gita_api.data.insert import (\n        authors,\n        languages,\n        chapters,\n        verses,\n        translations,\n        commentaries,\n    )\n\n    # importing the modules executes the code in it\n"
  },
  {
    "path": "bhagavad_gita_api/data/helpers.py",
    "content": "from urllib.request import urlopen\n\n\ndef remote_txt_file(url: str) -> str:\n    string = \"\"\n    file = urlopen(url)\n\n    for line in file:\n        decoded_line = line.decode(\"utf-8\")\n        string += decoded_line\n    return string\n\n\ndef gh_file_url(file, owner=\"gita\", repo=\"gita\", branch=\"main\", folder=\"data\"):\n    base = \"https://raw.githubusercontent.com\"\n    return f\"{base}/{owner}/{repo}/{branch}/{folder+'/' if folder else ''}{file}\"\n\n\ndef get_file(file):\n    return remote_txt_file(gh_file_url(file))\n"
  },
  {
    "path": "bhagavad_gita_api/data/insert/__init__.py",
    "content": ""
  },
  {
    "path": "bhagavad_gita_api/data/insert/authors.py",
    "content": "import json\n\nfrom rich.progress import track\nfrom sqlalchemy.orm import sessionmaker\n\nfrom bhagavad_gita_api.data.helpers import get_file\nfrom bhagavad_gita_api.db.session import engine\nfrom bhagavad_gita_api.models.gita import GitaAuthor\n\nSession = sessionmaker(bind=engine)\nsession = Session()\n\n\ncontent = get_file(\"authors.json\")\n\nli = []\ndata = json.loads(content)\n\nfor i in track(data, description=\"Loading authors\"):\n    li.append(\n        GitaAuthor(\n            name=i[\"name\"],\n            id=i[\"id\"],\n        )\n    )\nsession.add_all(li)\nsession.commit()\n"
  },
  {
    "path": "bhagavad_gita_api/data/insert/chapters.py",
    "content": "import json\n\nfrom rich.progress import track\nfrom sqlalchemy.orm import sessionmaker\n\nfrom bhagavad_gita_api.data.helpers import get_file\nfrom bhagavad_gita_api.db.session import engine\nfrom bhagavad_gita_api.models.gita import GitaChapter\n\nSession = sessionmaker(bind=engine)\nsession = Session()\n\ncontent = get_file(\"chapters.json\")\n\nli = []\ndata = json.loads(content)\n\nfor i in track(data, description=\"Loading chapters\"):\n    li.append(\n        GitaChapter(\n            id=i[\"id\"],\n            name=i[\"name\"],\n            name_transliterated=i[\"name_transliterated\"],\n            name_translated=i[\"name_translation\"],\n            verses_count=i[\"verses_count\"],\n            chapter_number=i[\"chapter_number\"],\n            name_meaning=i[\"name_meaning\"],\n            chapter_summary=i[\"chapter_summary\"],\n            chapter_summary_hindi=i[\"chapter_summary_hindi\"],\n            slug=f'chapter-{i[\"chapter_number\"]}-{i[\"name_translation\"].replace(\" \", \"-\").lower()}',\n        )\n    )\nsession.add_all(li)\nsession.commit()\n"
  },
  {
    "path": "bhagavad_gita_api/data/insert/commentaries.py",
    "content": "import json\n\nfrom rich.progress import track\nfrom sqlalchemy.orm import sessionmaker\n\nfrom bhagavad_gita_api.data.helpers import get_file\nfrom bhagavad_gita_api.db.session import engine\nfrom bhagavad_gita_api.models.gita import GitaCommentary\n\nSession = sessionmaker(bind=engine)\nsession = Session()\n\ncontent = get_file(\"commentary.json\")\n\n\nli = []\ndata = json.loads(content)\n\nfor i in track(data, description=\"Loading commentary\"):\n    li.append(\n        GitaCommentary(\n            description=i[\"description\"],\n            author_name=i[\"authorName\"],\n            language=i[\"lang\"],\n            verse_id=i[\"verseNumber\"],\n            author_id=i[\"author_id\"],\n            language_id=i[\"language_id\"],\n        )\n    )\nsession.add_all(li)\nsession.commit()\n"
  },
  {
    "path": "bhagavad_gita_api/data/insert/languages.py",
    "content": "import json\n\nfrom rich.progress import track\nfrom sqlalchemy.orm import sessionmaker\n\nfrom bhagavad_gita_api.data.helpers import get_file\nfrom bhagavad_gita_api.db.session import engine\nfrom bhagavad_gita_api.models.gita import GitaLanguage\n\nSession = sessionmaker(bind=engine)\nsession = Session()\n\ncontent = get_file(\"languages.json\")\n\n\nli = []\ndata = json.loads(content)\n\nfor i in track(data, description=\"Loading languages\"):\n    li.append(\n        GitaLanguage(\n            language=i[\"language\"],\n            id=i[\"id\"],\n        )\n    )\nsession.add_all(li)\nsession.commit()\n"
  },
  {
    "path": "bhagavad_gita_api/data/insert/translations.py",
    "content": "import json\n\nfrom rich.progress import track\nfrom sqlalchemy.orm import sessionmaker\n\nfrom bhagavad_gita_api.data.helpers import get_file\nfrom bhagavad_gita_api.db.session import engine\nfrom bhagavad_gita_api.models.gita import GitaTranslation\n\nSession = sessionmaker(bind=engine)\nsession = Session()\n\ncontent = get_file(\"translation.json\")\n\n\nli = []\ndata = json.loads(content)\n\nfor i in track(data, description=\"Loading translations\"):\n    li.append(\n        GitaTranslation(\n            description=i[\"description\"],\n            author_name=i[\"authorName\"],\n            language=i[\"lang\"],\n            verse_id=i[\"verseNumber\"],\n            author_id=i[\"author_id\"],\n            language_id=i[\"language_id\"],\n        )\n    )\nsession.add_all(li)\nsession.commit()\n"
  },
  {
    "path": "bhagavad_gita_api/data/insert/verses.py",
    "content": "import json\n\nfrom rich.progress import track\nfrom sqlalchemy.orm import sessionmaker\n\nfrom bhagavad_gita_api.data.helpers import get_file\nfrom bhagavad_gita_api.db.session import engine\nfrom bhagavad_gita_api.models.gita import GitaVerse\n\nSession = sessionmaker(bind=engine)\nsession = Session()\n\ncontent = get_file(\"verse.json\")\n\n\nli = []\ndata = json.loads(content)\n\nfor i in track(data, description=\"Loading verses\"):\n    li.append(\n        GitaVerse(\n            verse_number=i[\"verse_number\"],\n            chapter_number=i[\"chapter_number\"],\n            text=i[\"text\"],\n            id=i[\"id\"],\n            chapter_id=i[\"chapter_id\"],\n            transliteration=i[\"transliteration\"],\n            word_meanings=i[\"word_meanings\"],\n            slug=f'chapter-{i[\"chapter_number\"]}-verse-{i[\"verse_number\"]}',\n        )\n    )\nsession.add_all(li)\nsession.commit()\n"
  },
  {
    "path": "bhagavad_gita_api/db/__init__.py",
    "content": ""
  },
  {
    "path": "bhagavad_gita_api/db/base_class.py",
    "content": "from sqlalchemy.ext.declarative import declarative_base\n\nBase = declarative_base()\n"
  },
  {
    "path": "bhagavad_gita_api/db/init_db.py",
    "content": "from sqlalchemy.orm import Session\n\nfrom bhagavad_gita_api import crud\nfrom bhagavad_gita_api.config import settings\nfrom bhagavad_gita_api.data import insert_all\nfrom bhagavad_gita_api.db.base_class import Base\nfrom bhagavad_gita_api.db.session import engine\nfrom bhagavad_gita_api.models.gita import (  # NOQA\n    GitaAuthor,\n    GitaChapter,\n    GitaCommentary,\n    GitaLanguage,\n    GitaTranslation,\n    GitaVerse,\n)\nfrom bhagavad_gita_api.models.user import User\n\n# import all the models to create tables\n\n\ndef init_db(db: Session) -> None:\n    # add test user\n    user_in = crud.get_user(db, user_id=1)\n    new_db = False\n    if not user_in:\n        new_db = True\n        user_in = User(\n            id=1,\n            full_name=\"Radha Krishna\",\n            email=\"admin@bhagavadgita.io\",\n            app_name=\"BhagavadGita.io\",\n            app_description=\"BhagavadGita.io is a modern Bhagavad Gita app with a simple, beautiful and easy to use interface, helping you focus on reading. It is an app built for Bhagavad Gita readers, by Bhagavad Gita readers.\",\n            app_link=\"https://bhagavadgita.io\",\n            api_key=settings.TESTER_API_KEY,\n            is_active=True,\n        )\n\n        db.add(user_in)\n        db.commit()\n\n    Base.metadata.create_all(engine)\n    if new_db:\n        insert_all()\n"
  },
  {
    "path": "bhagavad_gita_api/db/session.py",
    "content": "from sqlalchemy import create_engine\nfrom sqlalchemy.orm import scoped_session, sessionmaker\n\nfrom bhagavad_gita_api.config import settings\nfrom bhagavad_gita_api.db.base_class import Base\n\nengine = create_engine(settings.SQLALCHEMY_DATABASE_URI, pool_pre_ping=True)\nSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)\n\nBase.metadata.create_all(engine)\ndb_session = scoped_session(\n    sessionmaker(autocommit=False, autoflush=False, bind=engine)\n)\nBase.query = db_session.query_property()\n"
  },
  {
    "path": "bhagavad_gita_api/graphql.py",
    "content": "from graphene import Int, List, ObjectType, String\nfrom graphene_sqlalchemy import SQLAlchemyObjectType\n\nfrom bhagavad_gita_api.db.session import db_session\nfrom bhagavad_gita_api.models.gita import (\n    GitaChapter,\n    GitaCommentary,\n    GitaTranslation,\n    GitaVerse,\n)\n\ndb = db_session.session_factory()\n\n\nclass GitaTranslationModel(SQLAlchemyObjectType):\n    class Meta:\n        model = GitaTranslation\n\n\nclass GitaCommentryModel(SQLAlchemyObjectType):\n    class Meta:\n        model = GitaCommentary\n\n\nclass GitaVerseModel(SQLAlchemyObjectType):\n    translations = List(\n        GitaTranslationModel,\n        authorName=String(),\n        language=String(),\n        limit=Int(),\n        first=Int(),\n        skip=Int(),\n    )\n    commentaries = List(\n        GitaCommentryModel,\n        authorName=String(),\n        language=String(),\n        limit=Int(),\n        first=Int(),\n        skip=Int(),\n    )\n\n    class Meta:\n        model = GitaVerse\n        exclude_fields = (\"translations\", \"commentaries\")\n\n        # filtering Pending\n\n    def resolve_translations(parent, info, **kwargs):\n\n        if parent.id:\n            verse_id = parent.id\n        else:\n            verse_id = (\n                db.query(GitaVerse)\n                .filter(\n                    GitaVerse.verse_number == parent.verse_number,\n                    GitaVerse.chapter_number == parent.chapter_number,\n                )\n                .with_entities(\n                    GitaVerse.id,\n                )\n                .first()\n            )[0]\n\n        if \"limit\" in kwargs.keys():\n\n            query = (\n                GitaTranslationModel.get_query(info)\n                .filter(GitaTranslation.verse_id == verse_id)\n                .limit(kwargs.get(\"limit\"))\n            )\n        elif \"authorName\" in kwargs.keys():\n            query = (\n                GitaTranslationModel.get_query(info)\n                .filter(GitaTranslation.author_name == kwargs.get(\"authorName\"))\n                .filter(GitaTranslation.verse_id == verse_id)\n            )\n\n        elif \"language\" in kwargs.keys():\n            query = (\n                GitaTranslationModel.get_query(info)\n                .filter(GitaTranslation.language == kwargs.get(\"language\"))\n                .filter(GitaTranslation.verse_id == verse_id)\n            )\n\n        else:\n            query = GitaTranslationModel.get_query(info).filter(\n                GitaTranslation.verse_id == verse_id\n            )\n\n        if \"skip\" in kwargs.keys():\n            query = query[kwargs.get(\"skip\") :]\n\n        if \"first\" in kwargs.keys():\n            query = query[: kwargs.get(\"first\")]\n\n        return query\n\n    def resolve_commentaries(parent, info, **kwargs):\n        verse_id = (\n            db.query(GitaVerse)\n            .filter(\n                GitaVerse.verse_number == parent.verse_number,\n                GitaVerse.chapter_number == parent.chapter_number,\n            )\n            .with_entities(\n                GitaVerse.id,\n            )\n            .first()\n        )[0]\n\n        if \"limit\" in kwargs.keys():\n\n            query = (\n                GitaCommentryModel.get_query(info)\n                .filter(GitaCommentary.verse_id == verse_id)\n                .limit(kwargs.get(\"limit\"))\n            )\n        elif \"authorName\" in kwargs.keys():\n            query = (\n                GitaCommentryModel.get_query(info)\n                .filter(GitaCommentary.author_name == kwargs.get(\"authorName\"))\n                .filter(GitaCommentary.verse_id == verse_id)\n            )\n\n        elif \"language\" in kwargs.keys():\n            query = (\n                GitaCommentryModel.get_query(info)\n                .filter(GitaCommentary.language == kwargs.get(\"language\"))\n                .filter(GitaCommentary.verse_id == verse_id)\n            )\n\n        else:\n            query = GitaCommentryModel.get_query(info).filter(\n                GitaCommentary.verse_id == verse_id\n            )\n\n        if \"skip\" in kwargs.keys():\n            query = query[kwargs.get(\"skip\") :]\n\n        if \"first\" in kwargs.keys():\n            query = query[: kwargs.get(\"first\")]\n\n        return query\n\n\nclass GitaChapterModel(SQLAlchemyObjectType):\n\n    verses = List(\n        GitaVerseModel,\n        verse_number=Int(),\n        limit=Int(),\n        first=Int(),\n        skip=Int(),\n    )\n\n    class Meta:\n        model = GitaChapter\n        exclude_fields = (\"verses\",)\n\n    def resolve_verses(parent, info, **kwargs):\n\n        if \"limit\" in kwargs.keys():\n            query = (\n                GitaVerseModel.get_query(info)\n                .filter(GitaVerse.chapter_number == parent.chapter_number)\n                .limit(kwargs.get(\"limit\"))\n            )\n\n        elif \"verse_number\" in kwargs.keys():\n            query = (\n                GitaVerseModel.get_query(info)\n                .filter(GitaVerse.verse_number == kwargs.get(\"verse_number\"))\n                .filter(GitaVerse.chapter_number == parent.chapter_number)\n            )\n\n        else:\n            query = GitaVerseModel.get_query(info).filter(\n                GitaVerse.chapter_number == parent.chapter_number\n            )\n\n        if \"skip\" in kwargs.keys():\n            query = query[kwargs.get(\"skip\") :]\n\n        if \"first\" in kwargs.keys():\n            query = query[: kwargs.get(\"first\")]\n\n        return query\n\n\nclass Query(ObjectType):\n    chapters = List(\n        GitaChapterModel,\n        chapter_number=Int(),\n        limit=Int(),\n        first=Int(),\n        skip=Int(),\n    )\n\n    verses = List(\n        GitaVerseModel,\n        verse_number=Int(),\n        verse_order=Int(),\n        limit=Int(),\n        first=Int(),\n        skip=Int(),\n    )\n\n    @staticmethod\n    async def resolve_chapters(self, info, **kwargs):\n\n        if \"chapter_number\" in kwargs.keys():\n            query = GitaChapterModel.get_query(info).filter(\n                GitaChapter.chapter_number == kwargs.get(\"chapter_number\")\n            )  # SQLAlchemy query\n        elif \"limit\" in kwargs.keys():\n            query = GitaChapterModel.get_query(info).limit(kwargs.get(\"limit\"))\n        else:\n\n            query = GitaChapterModel.get_query(info)  # SQLAlchemy query\n\n        if \"skip\" in kwargs.keys():\n            query = query[kwargs.get(\"skip\") :]\n\n        if \"first\" in kwargs.keys():\n            query = query[: kwargs.get(\"first\")]\n\n        return query\n\n    @staticmethod\n    async def resolve_verses(self, info, **kwargs):\n\n        if \"verse_number\" in kwargs.keys():\n            query = GitaVerseModel.get_query(info).filter(\n                GitaVerse.verse_number == kwargs.get(\"verse_number\")\n            )\n        elif \"verse_order\" in kwargs.keys():\n            query = GitaVerseModel.get_query(info).filter(\n                GitaVerse.id == kwargs.get(\"verse_order\")\n            )\n        elif \"limit\" in kwargs.keys():\n            query = GitaVerseModel.get_query(info).limit(kwargs.get(\"limit\"))\n        else:\n            query = GitaVerseModel.get_query(info)\n\n        if \"skip\" in kwargs.keys():\n            query = query[kwargs.get(\"skip\") :]\n\n        if \"first\" in kwargs.keys():\n            query = query[: kwargs.get(\"first\")]\n\n        return query\n"
  },
  {
    "path": "bhagavad_gita_api/gunicorn.conf.py",
    "content": "import multiprocessing\n\n# bind - The server socket to bind\nbind = \"0.0.0.0:8081\"\n\n# backlog - The maximum number of pending connections\n# Generally in range 64-2048\nbacklog = 2048\n\n# workers - The number of worker processes for handling requests.\n# A positive integer generally in the 2-4 x $(NUM_CORES) range\nworkers = multiprocessing.cpu_count() * 2 + 1\n\n# worker_class - The type of workers to use\n# A string referring to one of the following bundled classes:\n# 1. sync\n# 2. eventlet - Requires eventlet >= 0.9.7\n# 3. gevent - Requires gevent >= 0.13\n# 4. tornado - Requires tornado >= 0.2\n#\n# You’ll want to read http://docs.gunicorn.org/en/latest/design.html\n# for information on when you might want to choose one of the other\n# worker classes\nworker_class = \"uvicorn.workers.UvicornWorker\"\n\n# threads - The number of worker threads for handling requests. This will\n# run each worker with the specified number of threads.\n# A positive integer generally in the 2-4 x $(NUM_CORES) range\nthreads = 1\n\n# worker_connections - The maximum number of simultaneous clients\n# This setting only affects the Eventlet and Gevent worker types.\nworker_connections = 1000\n\n# max_requests - The maximum number of requests a worker will process\n# before restarting\n# Any value greater than zero will limit the number of requests a work\n# will process before automatically restarting. This is a simple method\n# to help limit the damage of memory leaks.\nmax_requests = 0\n\n# max_requests_jitter - The maximum jitter to add to the max-requests setting\n# The jitter causes the restart per worker to be randomized by\n# randint(0, max_requests_jitter). This is intended to stagger worker\n# restarts to avoid all workers restarting at the same time.\nmax_requests_jitter = 0\n\n# timeout - Workers silent for more than this many seconds are killed\n# and restarted\ntimeout = 30\n\n# graceful_timeout - Timeout for graceful workers restart\n# How max time worker can handle request after got restart signal.\n# If the time is up worker will be force killed.\ngraceful_timeout = 30\n\n# keep_alive - The number of seconds to wait for requests on a\n# Keep-Alive connection\n# Generally set in the 1-5 seconds range.\nkeep_alive = 2\n\n# accesslog - The Access log file to write to.\n# \"-\" means log to stdout.\naccesslog = \"-\"\n\n# errorlog - The Error log file to write to.\n# \"-\" means log to stderr.\nerrorlog = \"-\"\n\n# loglevel - The granularity of Error log outputs.\n# Valid level names are:\n# 1. debug\n# 2. info\n# 3. warning\n# 4. error\n# 5. critical\nloglevel = \"info\"\n"
  },
  {
    "path": "bhagavad_gita_api/main.py",
    "content": "import uvicorn\nfrom fastapi import Depends, FastAPI, HTTPException, Security, status\nfrom fastapi.middleware.cors import CORSMiddleware\nfrom fastapi.security.api_key import APIKeyHeader\nfrom sqlalchemy.orm import Session\n\nfrom bhagavad_gita_api.api import deps\nfrom bhagavad_gita_api.api.api_v2.api import api_router\nfrom bhagavad_gita_api.config import settings\nfrom bhagavad_gita_api.crud import get_valid_api_keys\n\nAPI_KEY_NAME = \"X-API-KEY\"\napi_key_header_auth = APIKeyHeader(name=API_KEY_NAME, auto_error=True)\n\n\nasync def get_api_key(\n    db: Session = Depends(deps.get_db),\n    api_key_header: str = Security(api_key_header_auth),\n) -> None:\n    if api_key_header not in get_valid_api_keys(db):\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Invalid API Key.\",\n        )\n\n\napp = FastAPI(\n    title=\"Bhagavad Gita API\",\n    description=\"The Bhagavad Gita Application Programming Interface (API) \"\n    \"allows a web or mobile developer to use the Bhagavad Gita text \"\n    \"in their web or mobile application(s). It is a RESTful API that \"\n    \"follows some of the Best Practices for designing a REST API which \"\n    \"makes it easy for developers to use and implement.\",\n    version=\"2.0\",\n)\napp.add_middleware(\n    CORSMiddleware,\n    allow_origins=\"*\",\n    allow_credentials=True,\n    allow_methods=[\"GET\", \"POST\"],\n    allow_headers=[\"*\"],\n)\n\n\n@app.get(\"/\", include_in_schema=False)\nasync def index():\n    return {\"message\": \"Hare Krishna!\"}\n\n\napp.include_router(\n    api_router,\n    prefix=settings.API_V2_STR,\n    dependencies=[Security(get_api_key, scopes=[\"openid\"])],\n)\n\n# app.add_route(\n#     \"/graphql\",\n#     GraphQLApp(executor_class=AsyncioExecutor, schema=graphene.Schema(query=Query)),\n# )\n\n\ndef cli():\n    # this function will be called when run from cli\n    uvicorn.run(\n        \"bhagavad_gita_api.main:app\",\n        host=\"0.0.0.0\",\n        port=8081,\n        reload=bool(settings.debug),\n    )\n"
  },
  {
    "path": "bhagavad_gita_api/models/__init__.py",
    "content": ""
  },
  {
    "path": "bhagavad_gita_api/models/gita.py",
    "content": "from sqlalchemy import Column, ForeignKey, Integer, String\nfrom sqlalchemy.orm import relationship\nfrom sqlalchemy.sql.schema import Index\nfrom sqlalchemy.sql.sqltypes import Date\nfrom sqlalchemy.types import UnicodeText\n\nfrom bhagavad_gita_api.db.base_class import Base\n\n\nclass GitaCommentary(Base):\n    __tablename__ = \"gita_commentaries\"\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    description = Column(UnicodeText)\n    author_name = Column(String(200))\n    language = Column(String(200))\n    verse_id = Column(Integer, ForeignKey(\"gita_verses.id\"))\n    author_id = Column(Integer, ForeignKey(\"gita_authors.id\"))\n    language_id = Column(Integer, ForeignKey(\"gita_languages.id\"))\n\n    __table_args__ = (Index(\"ix_commentary\", \"author_name\", \"language\", \"verse_id\"),)\n\n\nclass GitaTranslation(Base):\n    __tablename__ = \"gita_translations\"\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    description = Column(UnicodeText)\n    author_name = Column(String(200))\n    language = Column(String(100))\n    verse_id = Column(Integer, ForeignKey(\"gita_verses.id\"))\n    author_id = Column(Integer, ForeignKey(\"gita_authors.id\"))\n    language_id = Column(Integer, ForeignKey(\"gita_languages.id\"))\n\n    __table_args__ = (Index(\"ix_translation\", \"author_name\", \"language\", \"verse_id\"),)\n\n\nclass GitaLanguage(Base):\n    __tablename__ = \"gita_languages\"\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    language = Column(String(200))\n    translations = relationship(GitaTranslation, lazy=\"joined\")\n    commentaries = relationship(GitaCommentary, lazy=\"joined\")\n\n    __table_args__ = (Index(\"ix_language\", \"language\"),)\n\n\nclass GitaAuthor(Base):\n    __tablename__ = \"gita_authors\"\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    name = Column(String(200))\n    translations = relationship(GitaTranslation, backref=\"gitaAuthor\")\n    commentaries = relationship(GitaCommentary, backref=\"gitaAuthor\")\n\n    __table_args__ = (Index(\"ix_author\", \"name\"),)\n\n\nclass GitaVerse(Base):\n    __tablename__ = \"gita_verses\"\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    slug = Column(UnicodeText)\n    verse_number = Column(Integer)\n    chapter_number = Column(Integer)\n    text = Column(UnicodeText)\n    transliteration = Column(UnicodeText)\n    word_meanings = Column(UnicodeText)\n    chapter_id = Column(Integer, ForeignKey(\"gita_chapters.id\"))\n    translations = relationship(GitaTranslation, backref=\"gita_verses\", lazy=\"joined\")\n    commentaries = relationship(GitaCommentary, backref=\"gita_verses\", lazy=\"joined\")\n\n    __table_args__ = (Index(\"ix_verse\", \"chapter_number\", \"verse_number\", \"slug\"),)\n\n\nclass GitaChapter(Base):\n    __tablename__ = \"gita_chapters\"\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    name = Column(UnicodeText)\n    slug = Column(UnicodeText)\n    name_transliterated = Column(UnicodeText)\n    name_translated = Column(UnicodeText)\n    verses_count = Column(Integer)\n    chapter_number = Column(Integer)\n    name_meaning = Column(UnicodeText)\n    chapter_summary = Column(UnicodeText)\n    chapter_summary_hindi = Column(UnicodeText)\n    verses = relationship(GitaVerse, backref=\"gita_chapters\", lazy=\"joined\")\n\n    __table_args__ = (Index(\"ix_chapter\", \"chapter_number\", \"slug\"),)\n\n\nclass VerseOfDay(Base):\n    __tablename__ = \"verse_of_the_day\"\n\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    verse_order = Column(Integer)\n    date = Column(Date)\n"
  },
  {
    "path": "bhagavad_gita_api/models/schemas.py",
    "content": "from typing import List\n\nfrom pydantic import BaseModel\n\n\nclass BaseGitaModel(BaseModel):\n    id: int\n\n    class Config:\n        orm_mode = True\n\n\nclass GitaTranslation(BaseGitaModel):\n    description: str\n    author_name: str\n    language: str\n\n\nclass GitaCommentary(BaseGitaModel):\n    description: str\n    author_name: str\n    language: str\n\n\nclass GitaVerse(BaseGitaModel):\n    verse_number: int\n    chapter_number: int\n    slug: str\n    text: str\n    transliteration: str\n    word_meanings: str\n    translations: List[GitaTranslation] = []\n    commentaries: List[GitaCommentary] = []\n\n\nclass GitaVerseBase(BaseGitaModel):\n    verse_number: int\n    chapter_number: int\n    slug: str\n    text: str\n    transliteration: str\n    word_meanings: str\n\n\nclass GitaChapter(BaseGitaModel):\n    name: str\n    slug: str\n    name_transliterated: str\n    name_translated: str\n    verses_count: int\n    chapter_number: int\n    name_meaning: str\n    chapter_summary: str\n    chapter_summary_hindi: str\n\n\nclass VerseOfDay(BaseGitaModel):\n    id: int\n    verse_order: int\n"
  },
  {
    "path": "bhagavad_gita_api/models/user.py",
    "content": "from sqlalchemy import Boolean, Column, Integer, String\n\nfrom bhagavad_gita_api.db.base_class import Base\nfrom bhagavad_gita_api.utils import AwareDateTime, tzware_datetime\n\n\nclass User(Base):\n    __tablename__ = \"gita_users\"\n\n    id = Column(Integer, primary_key=True, index=True)\n    full_name = Column(String(128))\n    email = Column(String, unique=True, index=True)\n    app_name = Column(String, index=True)\n    app_description = Column(String, index=True)\n    app_link = Column(String(128))\n    api_key = Column(String, unique=True, index=True)\n    is_active = Column(Boolean, default=True)\n\n    created_on = Column(AwareDateTime(), default=tzware_datetime)\n"
  },
  {
    "path": "bhagavad_gita_api/utils.py",
    "content": "import datetime\n\nimport pytz\nfrom sqlalchemy import DateTime\nfrom sqlalchemy.types import TypeDecorator\n\n\ndef tzware_datetime():\n    \"\"\"\n    Return a timezone aware datetime.\n\n    :return: Datetime\n    \"\"\"\n    return datetime.datetime.now(pytz.utc)\n\n\nclass AwareDateTime(TypeDecorator):\n    \"\"\"\n    A DateTime type which can only store tz-aware DateTimes.\n\n    Source:\n      https://gist.github.com/inklesspen/90b554c864b99340747e\n    \"\"\"\n\n    cache_ok = True\n    impl = DateTime(timezone=True)\n\n    def process_bind_param(self, value, dialect):\n        if isinstance(value, datetime.datetime) and value.tzinfo is None:\n            raise ValueError(\"{!r} must be TZ-aware\".format(value))\n        return value\n\n    def __repr__(self):\n        return \"AwareDateTime()\"\n"
  },
  {
    "path": "cookie_iiradhakrishnaii.bot",
    "content": "sessionid=8275054554%3APKSLSH6uep9vTy%3A23; csrftoken=21M8J30VgJ2lZRG1jR6sRTu7gn8bxo6y; ds_user_id=8275054554;\n"
  },
  {
    "path": "docker-compose.dev.yml",
    "content": "version: \"3.7\"\n\nservices:\n  api:\n    container_name: gita-api\n    image: bhagavadgita/bhagavad-gita-api\n    build:\n      context: .\n      dockerfile: Dockerfile.dev\n    ports:\n      - 8081:8081\n    volumes:\n      - ./:/app\n    stdin_open: true\n    tty: true\n    depends_on:\n      - database\n    env_file:\n      - .env\n    restart: on-failure:5\n\n  database:\n    container_name: gita-db\n    image: postgres:12-alpine\n    volumes:\n      - ./db_data:/var/lib/postgresql\n    env_file:\n      - .env\n    restart: on-failure:5\n\n  redis-server:\n    container_name: gita-redis\n    image: redis:6.0-alpine\n    restart: on-failure:5\n\n  celery-worker:\n    container_name: gita-celery-worker\n    image: bhagavadgita/bhagavad-gita-api\n    command: celery -A bhagavad_gita_api.cronjobs worker -l INFO\n    depends_on:\n      - api\n      - redis-server\n    env_file:\n      - .env\n    restart: on-failure:5\n\n  celery-beat-worker:\n    container_name: gita-celery-beat-worker\n    image: bhagavadgita/bhagavad-gita-api\n    command: celery -A bhagavad_gita_api.cronjobs beat -l INFO\n    depends_on:\n      - api\n      - redis-server\n    env_file:\n      - .env\n    restart: on-failure:5\n"
  },
  {
    "path": "docker-compose.prod.yml",
    "content": "version: \"3.7\"\n\nservices:\n  api:\n    container_name: gita-api\n    image: bhagavadgita/bhagavad-gita-api\n    build:\n      context: .\n      dockerfile: Dockerfile.prod\n    ports:\n      - 8081:8081\n    env_file:\n      - .env\n    restart: unless-stopped\n\n  caddy:\n    image: caddy/caddy:2.2.1-alpine\n    container_name: caddy-service\n    restart: unless-stopped\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n    volumes:\n      - $PWD/Caddyfile:/etc/caddy/Caddyfile\n      - $PWD/site:/srv\n      - caddy_data:/data\n      - caddy_config:/config\n\n  redis-server:\n    container_name: gita-redis\n    image: redis:6.0-alpine\n    restart: unless-stopped\n\n  celery-worker:\n    container_name: gita-celery-worker\n    image: bhagavadgita/bhagavad-gita-api\n    command: celery -A bhagavad_gita_api.cronjobs worker -l INFO\n    depends_on:\n      - api\n      - redis-server\n    env_file:\n      - .env\n    restart: unless-stopped\n\n  celery-beat-worker:\n    container_name: gita-celery-beat-worker\n    image: bhagavadgita/bhagavad-gita-api\n    command: celery -A bhagavad_gita_api.cronjobs beat -l INFO\n    depends_on:\n      - api\n      - redis-server\n    env_file:\n      - .env\n    restart: unless-stopped\n\nvolumes:\n  caddy_data:\n  caddy_config:\n"
  },
  {
    "path": "mypy.ini",
    "content": "[mypy]\n\n# --strict\ndisallow_any_generics = True\ndisallow_subclassing_any = True\ndisallow_untyped_calls = True\ndisallow_untyped_defs = True\ndisallow_incomplete_defs = True\ncheck_untyped_defs = True\ndisallow_untyped_decorators = True\nno_implicit_optional = True\nwarn_redundant_casts = True\nwarn_unused_ignores = True\nwarn_return_any = True\nimplicit_reexport = False\nstrict_equality = True\n# --strict end\n\n[mypy-fastapi.concurrency]\nwarn_unused_ignores = False\nignore_missing_imports = True\n\n[mypy-fastapi.tests.*]\nignore_missing_imports = True\ncheck_untyped_defs = True\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[tool.poetry]\nname = \"bhagavad-gita-api\"\nversion = \"2.0.2\"\ndescription = \"Bhagavad Gita API allows any developer to use content from Bhagavad Gita in their applications.\"\nauthors = [\"The Gita Initiative <contact@bhagavadgita.io>\"]\nlicense = \"MIT\"\nreadme = \"README.md\"\nhomepage = \"https://bhagavadgita.io/\"\nrepository = \"https://github.com/gita/bhagavad-gita-api\"\nkeywords = [\"python\",\"fastapi\",\"api\",\"gita\",\"bhagavad-gita\"]\nclassifiers = [\n  \"License :: OSI Approved :: MIT License\",\n  \"Natural Language :: English\",\n  \"Operating System :: OS Independent\",\n  \"Programming Language :: Python\",\n  \"Intended Audience :: Education\",\n  \"Intended Audience :: Information Technology\",\n  \"Development Status :: 4 - Beta\",\n]\n\n[tool.poetry.dependencies]\npython = \"^3.8\"\nfastapi = \"^0.65.2\"\ngraphene-elastic = \"^0.7\"\npsycopg2-pgevents = \"^0.2.2\"\nSQLAlchemy = \"^1.4.19\"\nuvicorn = \"^0.14.0\"\ngraphene-sqlalchemy = \"^2.3.0\"\ngraphene-sqlalchemy-filter = \"^1.12.2\"\npython-dotenv = \"^0.18.0\"\npytz = \"^2021.1\"\nrich = \"^10.4.0\"\ngraphene = \"^2.1.8\"\ntyper = \"^0.3.2\"\ngunicorn = \"^20.1.0\"\ncelery = \"^5.1.2\"\nredis = \"^3.5.3\"\ntextwrap3 = \"^0.9.2\"\nPillow = \"^9.0.0\"\ntweepy = \"^4.4.0\"\nbs4 = \"^0.0.1\"\n\n[tool.poetry.dev-dependencies]\npre-commit = \"^2.13.0\"\nblack = \"^21.6b0\"\nisort = \"^5.9.1\"\nflake8 = \"^3.9.2\"\nautoflake = \"^1.4\"\nipykernel = \"^5.5.5\"\n\n[build-system]\nrequires = [\"poetry-core>=1.0.0\"]\nbuild-backend = \"poetry.core.masonry.api\"\n\n[tool.poetry.scripts]\nbhagavad-gita-api = 'bhagavad_gita_api.main:cli'\ngita-api = 'bhagavad_gita_api.main:cli'\n\n[tool.isort]\nprofile = \"black\"\nknown_third_party = [\"PIL\", \"bs4\", \"celery\", \"dotenv\", \"fastapi\", \"graphene\", \"graphene_sqlalchemy\", \"pydantic\", \"pytz\", \"requests\", \"rich\", \"sqlalchemy\", \"textwrap3\", \"tweepy\", \"typer\", \"uvicorn\"]\n\n[tool.black]\nline-length = 88\ninclude = '\\.pyi?$'\nexclude = '''\n(\n  /(\n      \\.eggs         # exclude a few common directories in the\n    | \\.git          # root of the project\n    | \\.hg\n    | \\.mypy_cache\n    | \\.tox\n    | \\.venv\n    | _build\n    | buck-out\n    | build\n    | dist\n  )/\n  | foo.py           # also separately exclude a file named foo.py in\n                     # the root of the project\n)\n'''\n"
  },
  {
    "path": "wait_for_db.sh",
    "content": "#!/bin/sh\n\necho \"Waiting for postgres...\"\n\nwhile ! nc -z $DB_HOST $DB_PORT; do\n  echo \"couldn't connect to database @ $DB_HOST:$DB_PORT retrying in 1 second ...\"\n  sleep 1\ndone\n\necho \"PostgreSQL started\"\n\n# sleep for 2 seconds for the database to be ready to accept connections\nsleep 2\n\n# create tables and seed data to database\n# TODO change this after adding alembic migrations\npython bhagavad_gita_api/cli.py seed-data\n\n# below line is to tell docker to continue the rest of the build flow\nexec \"$@\"\n"
  }
]