├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ ├── bugs.yaml │ └── features.yml ├── PR │ └── pull_request_template.md ├── codeql │ └── codeql-config.yml ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── build_exe.yml │ ├── codeql.yml │ ├── create_release.yml │ ├── python-publish.yml │ └── python-tests.yml ├── .gitignore ├── .readthedocs.yml ├── Examples ├── AutoResponder │ ├── auto_dm_responder.py │ └── auto_dm_responder_example.png ├── AutomaticGeneration │ ├── main_autochannel.py │ └── main_autoguild.py ├── DynamicModification │ ├── main_add_object.py │ ├── main_remove_object.py │ └── main_update.py ├── Logging │ ├── CSV │ │ ├── History │ │ │ └── 2024 │ │ │ │ └── 01 │ │ │ │ └── 24 │ │ │ │ └── zajcek's dungeon.csv │ │ └── main_csv_logging.py │ ├── JSON │ │ ├── History │ │ │ ├── 2023 │ │ │ │ ├── 10 │ │ │ │ │ ├── 10 │ │ │ │ │ │ └── zajcek's dungeon.json │ │ │ │ │ └── 09 │ │ │ │ │ │ ├── zajcek's dungeon.json │ │ │ │ │ │ └── zajcek's dungeon1.json │ │ │ │ └── 12 │ │ │ │ │ ├── 01 │ │ │ │ │ └── zajcek's dungeon.json │ │ │ │ │ └── 02 │ │ │ │ │ └── zajcek's dungeon.json │ │ │ └── 2024 │ │ │ │ └── 01 │ │ │ │ ├── 11 │ │ │ │ ├── zajcek's dungeon.json │ │ │ │ ├── zajcek's dungeon1.json │ │ │ │ ├── zajcek's dungeon2.json │ │ │ │ ├── zajcek's dungeon3.json │ │ │ │ ├── zajcek's dungeon4.json │ │ │ │ ├── zajcek's dungeon5.json │ │ │ │ └── zajcek's dungeon6.json │ │ │ │ ├── 12 │ │ │ │ ├── zajcek's dungeon.json │ │ │ │ ├── zajcek's dungeon1.json │ │ │ │ └── zajcek's dungeon2.json │ │ │ │ ├── 13 │ │ │ │ └── zajcek's dungeon.json │ │ │ │ ├── 18 │ │ │ │ └── zajcek's dungeon.json │ │ │ │ ├── 19 │ │ │ │ ├── magic-123-magic.json │ │ │ │ ├── zajcek's dungeon.json │ │ │ │ └── zajcek.json │ │ │ │ ├── 20 │ │ │ │ └── zajcek's dungeon.json │ │ │ │ ├── 22 │ │ │ │ └── zajcek's dungeon.json │ │ │ │ ├── 23 │ │ │ │ ├── magic-123-magic.json │ │ │ │ └── zajcek.json │ │ │ │ └── 24 │ │ │ │ ├── zajcek's dungeon.json │ │ │ │ └── zajcek.json │ │ └── main_json_logging.py │ └── SQL │ │ └── main_sql_logging.py ├── MessageTypes │ ├── DirectMESSAGE │ │ └── main_send_multiple.py │ ├── TextMESSAGE │ │ ├── main_send_dynamic.py │ │ └── main_send_multiple.py │ └── VoiceMESSAGE │ │ ├── VoiceMessage.mp3 │ │ ├── main_send.py │ │ └── main_send_dynamic.py └── Web │ └── main_web.py ├── LICENSE.md ├── MANIFEST.in ├── Patches ├── 1_client.patch ├── 2_http.patch ├── 3_gateway.patch ├── 4_version.patch ├── 5_interactions.patch ├── 6_embeds.patch └── 7_state.patch ├── README.rst ├── docs ├── Makefile ├── build-latex-win.sh ├── dep_local.json ├── images │ ├── .$sql_er.drawio.svg.bkp │ ├── daf-console-run.png │ ├── daf-gui-front-edit-msg.png │ ├── daf-gui-front.png │ ├── logo.png │ └── sql_er.drawio.svg ├── setup.py ├── source │ ├── changelog.rst │ ├── conf.py │ ├── dep_local.json │ ├── guide │ │ ├── GUI │ │ │ ├── analytics.rst │ │ │ ├── control.rst │ │ │ ├── filegen.rst │ │ │ ├── images │ │ │ │ ├── edit-remoteconnectionclient.png │ │ │ │ ├── gui-analytics-invite-frame-get-logs.png │ │ │ │ ├── gui-analytics-invite-frame-view-log.png │ │ │ │ ├── gui-analytics-invite-frame.png │ │ │ │ ├── gui-analytics-message-frame-get-logs.png │ │ │ │ ├── gui-analytics-message-frame-view-log.png │ │ │ │ ├── gui-analytics-message-frame.png │ │ │ │ ├── gui-analytics-num-invite-frame-calc.png │ │ │ │ ├── gui-analytics-num-invite-frame.png │ │ │ │ ├── gui-analytics-num-message-frame-calc.png │ │ │ │ ├── gui-analytics-num-message-frame.png │ │ │ │ ├── gui-analytics-tab.png │ │ │ │ ├── gui-connection-select.png │ │ │ │ ├── gui-defined-accounts-list.png │ │ │ │ ├── gui-depend-install.png │ │ │ │ ├── gui-live-view-add-object.png │ │ │ │ ├── gui-live-view-autochannel-view-property-channels.png │ │ │ │ ├── gui-live-view-edit-account.png │ │ │ │ ├── gui-live-view-property-view-autochannel.png │ │ │ │ ├── gui-live-view.png │ │ │ │ ├── gui-load-accounts-bnts.png │ │ │ │ ├── gui-logger-definition-edit-json.png │ │ │ │ ├── gui-logger-definition-tracing.png │ │ │ │ ├── gui-messages-sent-post-acc-definition.png │ │ │ │ ├── gui-new-account-window.png │ │ │ │ ├── gui-new-item-define-string-window.png │ │ │ │ ├── gui-new-item-define.png │ │ │ │ ├── gui-new-item-edit-string-window.png │ │ │ │ ├── gui-new-item-edit.png │ │ │ │ ├── gui-new-server-list.png │ │ │ │ ├── gui-predefined-value-select.png │ │ │ │ ├── gui-schema-backup-bnt.png │ │ │ │ ├── gui-schema-backup-file-save.png │ │ │ │ ├── gui-schema-restore-bnt.png │ │ │ │ ├── gui-shill-script-gen-bnt.png │ │ │ │ ├── gui-start-stop-bnt.png │ │ │ │ ├── gui-started-output-defined-accounts.png │ │ │ │ ├── new-account-template-bnt.png │ │ │ │ ├── open-logger-definition.png │ │ │ │ ├── run-windows-daf-gui.png │ │ │ │ ├── schema.json │ │ │ │ └── shill_script.py │ │ │ ├── index.rst │ │ │ ├── live_view.rst │ │ │ ├── quickstart.rst │ │ │ ├── remote.rst │ │ │ └── schema.rst │ │ ├── core │ │ │ ├── autogen.rst │ │ │ ├── autoresponder.rst │ │ │ ├── control.rst │ │ │ ├── images │ │ │ │ ├── captcha.png │ │ │ │ ├── logging_process.drawio.svg │ │ │ │ ├── message_definition_example_output.png │ │ │ │ └── search_update_method.png │ │ │ ├── index.rst │ │ │ ├── logging.rst │ │ │ ├── logic.rst │ │ │ ├── modification.rst │ │ │ ├── remote.rst │ │ │ ├── shilldefine.rst │ │ │ └── web.rst │ │ ├── dep_local.json │ │ ├── images │ │ │ ├── copy-snowflake-id.png │ │ │ └── daf-console-run.png │ │ └── index.rst │ ├── images │ │ └── changelog_2_1_slippage_fix.png │ ├── index.rst │ └── scripts │ │ └── generate_autodoc.py └── thesis │ ├── ExampleUsage │ ├── example-autoguild-autochannel.json │ ├── example-autoguild-autochannel.py │ ├── example-invites-tracking.json │ ├── example-invites-tracking.py │ ├── example-new-guild-join.json │ ├── example-new-guild-join.py │ ├── example-remote.json │ ├── example-remote.py │ ├── example-text-message-randomized-period.json │ └── example-text-message-randomized-period.py │ ├── IzjavaOAvtorstvu.pdf │ ├── NaslovnaStranDiplome.pdf │ ├── conf.py │ ├── daf-thesis.pdf │ ├── dep_local.json │ ├── images │ ├── autodoc_example.png │ ├── daf-account-layer-flowchart.svg │ ├── daf-core-http-api.drawio.svg │ ├── daf-gui-analytics-tab-rotated.png │ ├── daf-gui-front-rotated.png │ ├── daf-gui-live-view.png │ ├── daf-gui-modules-tab.png │ ├── daf-gui-output-tab.png │ ├── daf-guild-layer-flowchart.svg │ ├── daf-high-level-log.svg │ ├── daf-logging-json.svg │ ├── daf-message-period.svg │ ├── daf-message-process.svg │ ├── daf-selenium-layer.svg │ ├── daf_abstraction.drawio.svg │ ├── debug.log │ ├── discord-embedded-message.png │ ├── discord_client_struct.drawio.png │ ├── discord_direct_message_channel.png │ ├── discord_text_channel.png │ ├── discord_voice_channel.png │ ├── doc-pdf-download.png │ ├── example_bunny_nft.png │ ├── feuni_discord.png │ ├── ssfe_discord.png │ └── topgg_find_servers.png │ ├── pdfa-daf-thesis.pdf │ ├── scripts │ └── generate_lit.py │ ├── sl │ ├── abstract.rst │ ├── acknowledgements.rst │ ├── appendix.rst │ ├── conclusion.rst │ ├── daf │ │ ├── dep_local.json │ │ ├── design_development │ │ │ ├── core.rst │ │ │ ├── dep_local.json │ │ │ ├── docs.rst │ │ │ ├── gui.rst │ │ │ ├── index.rst │ │ │ └── testing.rst │ │ ├── index.rst │ │ └── purpose.rst │ ├── dep_local.json │ ├── discord.rst │ ├── glossary.rst │ ├── index.rst │ ├── introduction.rst │ └── titlepage.tex │ └── sources.json ├── pyproject.toml ├── requirements ├── docs.txt ├── mandatory.txt ├── sql.txt ├── testing.txt ├── voice.txt └── web.txt ├── setup_build_env_do_not_run ├── install.ps1 └── install.sh ├── src ├── _discord │ ├── __init__.py │ ├── __main__.py │ ├── _typed_dict.py │ ├── _version.py │ ├── abc.py │ ├── activity.py │ ├── appinfo.py │ ├── application_role_connection.py │ ├── asset.py │ ├── audit_logs.py │ ├── automod.py │ ├── backoff.py │ ├── bin │ │ ├── COPYING │ │ ├── libopus-0.x64.dll │ │ └── libopus-0.x86.dll │ ├── bot.py │ ├── channel.py │ ├── client.py │ ├── cog.py │ ├── colour.py │ ├── commands │ │ ├── __init__.py │ │ ├── context.py │ │ ├── core.py │ │ ├── options.py │ │ └── permissions.py │ ├── components.py │ ├── context_managers.py │ ├── embeds.py │ ├── emoji.py │ ├── enums.py │ ├── errors.py │ ├── ext │ │ ├── bridge │ │ │ ├── __init__.py │ │ │ ├── bot.py │ │ │ ├── context.py │ │ │ └── core.py │ │ ├── commands │ │ │ ├── __init__.py │ │ │ ├── _types.py │ │ │ ├── bot.py │ │ │ ├── cog.py │ │ │ ├── context.py │ │ │ ├── converter.py │ │ │ ├── cooldowns.py │ │ │ ├── core.py │ │ │ ├── errors.py │ │ │ ├── flags.py │ │ │ ├── help.py │ │ │ └── view.py │ │ ├── pages │ │ │ ├── __init__.py │ │ │ └── pagination.py │ │ └── tasks │ │ │ └── __init__.py │ ├── file.py │ ├── flags.py │ ├── gateway.py │ ├── guild.py │ ├── http.py │ ├── integrations.py │ ├── interactions.py │ ├── invite.py │ ├── iterators.py │ ├── member.py │ ├── mentions.py │ ├── message.py │ ├── mixins.py │ ├── object.py │ ├── oggparse.py │ ├── opus.py │ ├── partial_emoji.py │ ├── permissions.py │ ├── player.py │ ├── py.typed │ ├── raw_models.py │ ├── reaction.py │ ├── role.py │ ├── scheduled_events.py │ ├── shard.py │ ├── sinks │ │ ├── __init__.py │ │ ├── core.py │ │ ├── errors.py │ │ ├── m4a.py │ │ ├── mka.py │ │ ├── mkv.py │ │ ├── mp3.py │ │ ├── mp4.py │ │ ├── ogg.py │ │ ├── pcm.py │ │ └── wave.py │ ├── stage_instance.py │ ├── state.py │ ├── sticker.py │ ├── team.py │ ├── template.py │ ├── threads.py │ ├── types │ │ ├── __init__.py │ │ ├── activity.py │ │ ├── appinfo.py │ │ ├── application_role_connection.py │ │ ├── audit_log.py │ │ ├── automod.py │ │ ├── channel.py │ │ ├── components.py │ │ ├── embed.py │ │ ├── emoji.py │ │ ├── gateway.py │ │ ├── guild.py │ │ ├── integration.py │ │ ├── interactions.py │ │ ├── invite.py │ │ ├── member.py │ │ ├── message.py │ │ ├── raw_models.py │ │ ├── role.py │ │ ├── scheduled_events.py │ │ ├── snowflake.py │ │ ├── sticker.py │ │ ├── team.py │ │ ├── template.py │ │ ├── threads.py │ │ ├── user.py │ │ ├── voice.py │ │ ├── webhook.py │ │ ├── welcome_screen.py │ │ └── widget.py │ ├── ui │ │ ├── __init__.py │ │ ├── button.py │ │ ├── input_text.py │ │ ├── item.py │ │ ├── modal.py │ │ ├── select.py │ │ └── view.py │ ├── user.py │ ├── utils.py │ ├── voice_client.py │ ├── webhook │ │ ├── __init__.py │ │ ├── async_.py │ │ └── sync.py │ ├── welcome_screen.py │ └── widget.py ├── daf │ ├── __init__.py │ ├── client.py │ ├── convert.py │ ├── core.py │ ├── dtypes.py │ ├── events.py │ ├── guild │ │ ├── __init__.py │ │ ├── autoguild.py │ │ └── guilduser.py │ ├── logging │ │ ├── __init__.py │ │ ├── _logging │ │ │ └── __init__.py │ │ ├── logger_base.py │ │ ├── logger_csv.py │ │ ├── logger_file.py │ │ ├── logger_json.py │ │ ├── sql │ │ │ ├── __init__.py │ │ │ ├── mgr.py │ │ │ └── tables.py │ │ └── tracing.py │ ├── logic.py │ ├── message │ │ ├── __init__.py │ │ ├── autochannel.py │ │ ├── base.py │ │ ├── constraints.py │ │ ├── messageperiod.py │ │ ├── text_based.py │ │ └── voice_based.py │ ├── messagedata │ │ ├── __init__.py │ │ ├── basedata.py │ │ ├── dynamicdata.py │ │ ├── file.py │ │ ├── textdata.py │ │ └── voicedata.py │ ├── misc │ │ ├── __init__.py │ │ ├── async_util.py │ │ ├── attributes.py │ │ ├── cache.py │ │ ├── doc.py │ │ └── instance_track.py │ ├── remote.py │ ├── responder │ │ ├── __init__.py │ │ ├── actions │ │ │ ├── __init__.py │ │ │ └── response.py │ │ ├── base.py │ │ ├── constraints │ │ │ ├── __init__.py │ │ │ ├── baseconstraint.py │ │ │ ├── dmconstraint.py │ │ │ └── guildconstraint.py │ │ ├── dmresponder.py │ │ └── guildresponder.py │ └── web.py └── daf_gui │ ├── __init__.py │ ├── __main__.py │ ├── connector.py │ ├── edit_window_manager.py │ ├── img │ └── logo.png │ ├── main.py │ ├── tabs │ ├── __init__.py │ ├── about.py │ ├── analytics.py │ ├── debug.py │ ├── live.py │ ├── optional.py │ └── schema.py │ └── tod_extensions │ ├── convert.py │ ├── deprecation_notice.py │ ├── extra_widgets.py │ ├── help_button.py │ ├── live_objects.py │ ├── loader.py │ └── method_execution.py └── testing ├── conftest.py ├── fixtures ├── __init__.py └── main.py ├── test_autogen.py ├── test_events.py ├── test_logging.py ├── test_period_dynamic.py ├── test_remote.py ├── test_removal.py ├── test_responder.py ├── test_send_normal.py ├── test_serialization.py ├── test_update.py ├── test_util.py └── testing123.mp3 /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | min_python_version = 3.9 3 | 4 | exclude = src/_discord 5 | 6 | ignore = 7 | F403 8 | F405 9 | W504 10 | E251 11 | 12 | max-line-length = 120 13 | max-complexity=40 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bugs.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | title: "[Bug]: " 4 | labels: ["bug", "triage"] 5 | assignees: 6 | - octocat 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for taking the time to fill out this bug report! 12 | - type: textarea 13 | id: what-happened 14 | attributes: 15 | label: What happened? 16 | description: Also tell us, what did you expect to happen? 17 | placeholder: Tell us what you see! 18 | value: "A bug happened!" 19 | validations: 20 | required: true 21 | - type: input 22 | id: version 23 | attributes: 24 | label: Version 25 | description: What version of our software are you running? 26 | validations: 27 | required: true 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/features.yml: -------------------------------------------------------------------------------- 1 | name: "Feature Request" 2 | description: Request a new feature 3 | title: "[Enhancement:] " 4 | labels: 5 | ["enhancement"] 6 | body: 7 | - type: textarea 8 | id: summary 9 | attributes: 10 | label: "Summary" 11 | description: Provide a brief explanation of the feature 12 | placeholder: Describe in a few lines your feature request 13 | validations: 14 | required: true 15 | - type: textarea 16 | id: basic_example 17 | attributes: 18 | label: "Basic Example" 19 | description: Indicate here some basic examples of your feature. 20 | placeholder: A few specific words about your feature request. 21 | validations: 22 | required: true 23 | - type: textarea 24 | id: unresolved_question 25 | attributes: 26 | label: "Unresolved questions" 27 | description: What questions still remain unresolved ? 28 | placeholder: Identify any unresolved issues. 29 | validations: 30 | required: false -------------------------------------------------------------------------------- /.github/PR/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/codeql/codeql-config.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL config" 2 | 3 | paths: 4 | - src/daf -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | target-branch: "develop" 8 | commit-message: 9 | prefix: "depend" 10 | prefix-development: "depend" 11 | include: "scope" 12 | - package-ecosystem: "github-actions" 13 | directory: "/" 14 | schedule: 15 | interval: "daily" 16 | target-branch: "develop" 17 | commit-message: 18 | prefix: "ci" 19 | include: "scope" -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | Pull request type: 2 | - [ ] Feature 3 | - [ ] Bug fix 4 | - [ ] Documentation 5 | - [ ] Breaking change 6 | 7 | I have: 8 | - [ ] Tested the code 9 | - [ ] Wrote unit tests for the code 10 | - [ ] Documented changes: 11 | - [ ] Guide(s) 12 | - [ ] API reference 13 | - [ ] Changelog 14 | 15 | Changes: 16 | - 17 | -------------------------------------------------------------------------------- /.github/workflows/build_exe.yml: -------------------------------------------------------------------------------- 1 | name: Build DAF.exe 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build: 9 | runs-on: windows-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v4 13 | - name: Set up Python 14 | uses: actions/setup-python@v5 15 | with: 16 | python-version: "3.11" 17 | cache: 'pip' 18 | - name: Install required 19 | run: | 20 | pip install .[all] 21 | pip install pyinstaller 22 | - name: Build 23 | run: | 24 | echo "from daf_gui import run;run()" > discord-advert-framework.py 25 | pyinstaller --onefile --windowed discord-advert-framework.py --add-data src/daf_gui/img/:daf_gui/img/ --icon src/daf_gui/img/logo.png --add-data src/_discord/bin/:_discord/bin/ 26 | - name: Upload 27 | uses: softprops/action-gh-release@v2 28 | with: 29 | files: | 30 | dist/discord-advert-framework.exe 31 | -------------------------------------------------------------------------------- /.github/workflows/create_release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | inputs: 4 | version-major: 5 | type: string 6 | description: Major version (eg. x.0.0) 7 | version-minor: 8 | type: string 9 | description: Minor version (eg. 0.x.0) 10 | 11 | version-bugfix: 12 | type: string 13 | description: Bug fix version (eg. 0.0.x) 14 | default: "0" 15 | 16 | name: Create Release 17 | 18 | jobs: 19 | build: 20 | name: Create Release 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Checkout code 24 | uses: actions/checkout@master 25 | - name: Create tag 26 | id: tag_version 27 | uses: mathieudutour/github-tag-action@v6.2 28 | with: 29 | github_token: ${{ secrets.TOKEN_GH }} 30 | custom_tag : ${{github.event.inputs.version-major}}.${{github.event.inputs.version-minor}}.${{github.event.inputs.version-bugfix}} 31 | - name: Create Release 32 | id: create_release 33 | uses: actions/create-release@latest 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.TOKEN_GH }} # This token is provided by Actions, you do not need to create your own token 36 | with: 37 | tag_name: ${{ steps.tag_version.outputs.new_tag }} 38 | release_name: ${{ steps.tag_version.outputs.new_tag }} 39 | body: "Changelog: https://daf.davidhozic.com/en/v${{github.event.inputs.version-major}}.${{github.event.inputs.version-minor}}.x/changelog.html" 40 | draft: false 41 | prerelease: false 42 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to PyPi 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | workflow_dispatch: 8 | 9 | jobs: 10 | # Build job 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v4 16 | 17 | - name: Set up Python 18 | uses: actions/setup-python@v5 19 | with: 20 | python-version: "3.x" 21 | cache: 'pip' 22 | 23 | - name: Install dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | python -m pip install build 27 | 28 | - name: Build 29 | run: | 30 | python -m build 31 | 32 | - name: Publish package 33 | uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70 34 | with: 35 | user: __token__ 36 | password: ${{ secrets.PYPI_API_TOKEN }} 37 | -------------------------------------------------------------------------------- /.github/workflows/python-tests.yml: -------------------------------------------------------------------------------- 1 | name: Self-Test 2 | 3 | on: 4 | push: 5 | branches: [ "master"] 6 | pull_request: 7 | branches: [ "master" , "develop"] 8 | workflow_dispatch: 9 | 10 | concurrency: 11 | group: "selftest-cg" 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | pytest: 16 | runs-on: ubuntu-latest 17 | strategy: 18 | max-parallel: 1 19 | fail-fast: false 20 | matrix: 21 | python-version: ["3.9", "3.13"] 22 | steps: 23 | - uses: actions/checkout@v4 24 | - name: Set up Python ${{ matrix.python-version }} 25 | uses: actions/setup-python@v5 26 | with: 27 | python-version: ${{ matrix.python-version }} 28 | cache: 'pip' 29 | - name: Install APT dependencies 30 | run: | 31 | sudo apt-get update 32 | sudo apt install ffmpeg 33 | - name: Install Python dependencies 34 | run: | 35 | python -m pip install --upgrade pip 36 | pip install .[all] .[testing] 37 | - name: Test version compatibility 38 | env: 39 | DISCORD_TOKEN: ${{secrets.DATT}} 40 | if: ${{ matrix.python-version != 3.9 }} 41 | run: | 42 | pytest -v testing/test_period_dynamic.py 43 | - name: Test all 44 | env: 45 | DISCORD_TOKEN: ${{secrets.DATT}} 46 | if: ${{ matrix.python-version == 3.9 }} 47 | run: | 48 | pytest -v -m "not group_remote" 49 | pytest -v -m "group_remote" 50 | 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__/** 2 | dist/** 3 | build/** 4 | **egg-info** 5 | 6 | .vscode 7 | .idea 8 | 9 | docs/build 10 | docs/source/reference/ 11 | 12 | docs/thesis/*/thesis_lit.rst 13 | docs/thesis/reference/ 14 | 15 | docs/common/reference 16 | **/DEP/** 17 | 18 | daf_web_data 19 | test.py 20 | 21 | venv* 22 | .venv* 23 | 24 | *.bkp 25 | *.dtmp 26 | 27 | .env 28 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | formats: [ 3 | "pdf" 4 | ] 5 | 6 | sphinx: 7 | configuration: docs/source/conf.py 8 | fail_on_warning: false 9 | 10 | build: 11 | os: ubuntu-22.04 12 | apt_packages: 13 | - inkscape 14 | tools: 15 | python: "3.12" 16 | jobs: 17 | pre_build: 18 | - pip install .[all] .[docs] 19 | - python3 ./docs/setup.py --start-dir source 20 | -------------------------------------------------------------------------------- /Examples/AutoResponder/auto_dm_responder.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | The example shows how to use the automatic responder feature. 4 | 5 | DMResponder is used. It listens to messages inside DMs. 6 | RegEx (regex) is used to match the text pattern. 7 | MemberOfGuildConstraint is used for ensuring the author of the dm message is a member 8 | of guild with ID 863071397207212052. 9 | """ 10 | # Import the necessary items 11 | from _discord.flags import Intents 12 | from daf.messagedata.textdata import TextMessageData 13 | from daf.responder.constraints.dmconstraint import MemberOfGuildConstraint 14 | from daf.client import ACCOUNT 15 | from daf.responder.dmresponder import DMResponder 16 | from daf.responder.actions.response import DMResponse 17 | from daf.logic import regex 18 | import daf 19 | 20 | 21 | # Defined accounts 22 | intents = Intents.default() 23 | intents.members=True 24 | intents.guild_messages=True 25 | intents.dm_messages=True 26 | intents.message_content=True 27 | 28 | accounts = [ 29 | ACCOUNT( 30 | token="CLIENT_TOKEN_HERE", 31 | is_user=False, 32 | intents=intents, 33 | responders=[ 34 | DMResponder( 35 | condition=regex( 36 | pattern="(buy|sell).*nft", 37 | ), 38 | action=DMResponse( 39 | data=TextMessageData( 40 | content="Instructions on how to buy / sell NFTs are provided on our official website:\nhttps://daf.davidhozic.com", 41 | ), 42 | ), 43 | constraints=[ 44 | MemberOfGuildConstraint( 45 | guild=863071397207212052, 46 | ), 47 | ], 48 | ), 49 | ], 50 | ), 51 | ] 52 | 53 | # Run the framework (blocking) 54 | daf.run( 55 | accounts=accounts 56 | ) 57 | -------------------------------------------------------------------------------- /Examples/AutoResponder/auto_dm_responder_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/Examples/AutoResponder/auto_dm_responder_example.png -------------------------------------------------------------------------------- /Examples/AutomaticGeneration/main_autochannel.py: -------------------------------------------------------------------------------- 1 | # Import the necessary items 2 | from daf.logging.logger_json import LoggerJSON 3 | 4 | from daf.guild.autoguild import AutoGUILD 5 | from daf.logic import or_ 6 | from daf.messagedata.textdata import TextMessageData 7 | from datetime import timedelta 8 | from daf.message.autochannel import AutoCHANNEL 9 | from daf.message.messageperiod import FixedDurationPeriod 10 | from daf.message.text_based import TextMESSAGE 11 | from daf.logic import contains 12 | from daf.client import ACCOUNT 13 | from daf.logging.tracing import TraceLEVELS 14 | import daf 15 | 16 | # Define the logger 17 | logger = LoggerJSON( 18 | path="C:\\Users\\david\\daf\\History", 19 | ) 20 | 21 | # Define remote control context 22 | 23 | 24 | # Defined accounts 25 | accounts = [ 26 | ACCOUNT( 27 | token="TOKEN_HERE", 28 | is_user=True, 29 | servers=[ 30 | AutoGUILD( 31 | include_pattern=or_( 32 | operands=[ 33 | contains(keyword="shill"), 34 | contains(keyword="NFT"), 35 | contains(keyword="dragon"), 36 | contains(keyword="promo"), 37 | ], 38 | ), 39 | messages=[ 40 | TextMESSAGE( 41 | data=TextMessageData(content="Checkout my new Red Dragon NFT! Additionaly, we also have the Golden Dragon - limited time only!"), 42 | channels=AutoCHANNEL( 43 | include_pattern=or_( 44 | operands=[ 45 | contains(keyword="nft"), 46 | contains(keyword="shill"), 47 | contains(keyword="self-promo"), 48 | contains(keyword="projects"), 49 | contains(keyword="marketing"), 50 | ], 51 | ), 52 | ), 53 | period=FixedDurationPeriod(duration=timedelta(seconds=5.0)), 54 | ), 55 | ], 56 | logging=True, 57 | ), 58 | ], 59 | ), 60 | ] 61 | 62 | # Run the framework (blocking) 63 | daf.run( 64 | accounts=accounts, 65 | logger=logger, 66 | debug=TraceLEVELS.NORMAL, 67 | save_to_file=False 68 | ) 69 | -------------------------------------------------------------------------------- /Examples/AutomaticGeneration/main_autoguild.py: -------------------------------------------------------------------------------- 1 | # Import the necessary items 2 | from daf.logging.logger_json import LoggerJSON 3 | 4 | from daf.client import ACCOUNT 5 | from daf.logic import contains 6 | from daf.guild.autoguild import AutoGUILD 7 | from daf.logic import or_ 8 | from daf.logging.tracing import TraceLEVELS 9 | import daf 10 | 11 | # Define the logger 12 | logger = LoggerJSON( 13 | path="C:\\Users\\david\\daf\\History", 14 | ) 15 | 16 | # Define remote control context 17 | 18 | 19 | # Defined accounts 20 | accounts = [ 21 | ACCOUNT( 22 | token="TOKEN_HERE", 23 | is_user=True, 24 | servers=[ 25 | AutoGUILD( 26 | include_pattern=or_( 27 | operands=[ 28 | contains(keyword="shill"), 29 | contains(keyword="NFT"), 30 | contains(keyword="dragon"), 31 | contains(keyword="promo"), 32 | ], 33 | ), 34 | logging=True, 35 | ), 36 | ], 37 | ), 38 | ] 39 | 40 | # Run the framework (blocking) 41 | daf.run( 42 | accounts=accounts, 43 | logger=logger, 44 | debug=TraceLEVELS.NORMAL, 45 | save_to_file=False 46 | ) 47 | -------------------------------------------------------------------------------- /Examples/DynamicModification/main_add_object.py: -------------------------------------------------------------------------------- 1 | """ 2 | The example shows how to dynamically add objects to the framework 3 | after it had already been run. 4 | """ 5 | from datetime import timedelta 6 | import daf 7 | 8 | 9 | async def user_task(): 10 | # Returns the client to send commands to discord, for more info about client see https://docs.pycord.dev/en/master/api.html?highlight=discord%20client#discord.Client 11 | account = daf.ACCOUNT(token="ASDASJDAKDK", is_user=False) 12 | guild = daf.GUILD(snowflake=123456) 13 | data_to_shill = daf.TextMessageData( 14 | "Hello World", 15 | daf.discord.Embed(title="Example Embed", color=daf.discord.Color.blue(), description="This is a test embed") 16 | ) 17 | text_msg = daf.TextMESSAGE( 18 | data=data_to_shill, 19 | channels=[12345, 6789], 20 | period=daf.FixedDurationPeriod(timedelta(minutes=1)) 21 | ) 22 | 23 | # Dynamically add account 24 | await daf.add_object(account) 25 | 26 | # Dynamically add guild 27 | await account.add_server(guild) 28 | # await daf.add_object(guild, account) 29 | 30 | # Dynamically add message 31 | await guild.add_message(text_msg) 32 | # await daf.add_object(text_msg, guild) 33 | 34 | 35 | ############################################################################################ 36 | if __name__ == "__main__": 37 | daf.run(user_callback=user_task) 38 | -------------------------------------------------------------------------------- /Examples/DynamicModification/main_remove_object.py: -------------------------------------------------------------------------------- 1 | """ 2 | The following example uses a predefined list of messages to shill. 3 | When the user task is run, it removes the message from the shill list dynamically. 4 | """ 5 | import daf 6 | 7 | accounts = [ 8 | account := daf.ACCOUNT( 9 | token="SDSADSDA87sd87", 10 | is_user=False, 11 | servers=[ 12 | daf.GUILD(snowflake=213323123, messages=[]) # No messages as not needed for this demonstration 13 | ] 14 | ) 15 | ] 16 | 17 | 18 | async def user_task(): 19 | guild = account.servers[0] 20 | await daf.remove_object(guild) 21 | 22 | 23 | ############################################################################################ 24 | if __name__ == "__main__": 25 | daf.run(user_callback=user_task, accounts=accounts) 26 | -------------------------------------------------------------------------------- /Examples/DynamicModification/main_update.py: -------------------------------------------------------------------------------- 1 | """ 2 | The following example shows how to update the object to run on 3 | new parameters. 4 | It is generally not recommended to use this if there is a better way, 5 | for example if you want to change the message, it's better to just create 6 | a new message object, however the only way to update SQL manager for logging is via the 7 | update method. 8 | """ 9 | from datetime import timedelta 10 | import asyncio 11 | import daf 12 | 13 | 14 | message = daf.TextMESSAGE( 15 | data=daf.TextMessageData("Hello"), 16 | channels=[123455, 1425215], 17 | period=daf.FixedDurationPeriod(timedelta(seconds=5)) 18 | ) 19 | 20 | accounts = [ 21 | daf.ACCOUNT( 22 | token="SKJDSKAJDKSJDKLAJSKJKJKGSAKGJLKSJG", 23 | is_user=False, 24 | servers=[ 25 | daf.GUILD(1234567, [message]) 26 | ] 27 | ) 28 | ] 29 | 30 | 31 | async def user_task(): 32 | # Will send "Hello" every 5 seconds 33 | await asyncio.sleep(10) 34 | await message.update( 35 | period=daf.FixedDurationPeriod(timedelta(seconds=20)), 36 | ) 37 | # Will send "Hello" every 20 seconds 38 | 39 | if __name__ == "__main__": 40 | daf.run(user_callback=user_task, accounts=accounts) 41 | -------------------------------------------------------------------------------- /Examples/Logging/CSV/History/2024/01/24/zajcek's dungeon.csv: -------------------------------------------------------------------------------- 1 | 436766310739971;"24.01.2024 18:46:41";"GUILD";"zajcek's dungeon";863071397207212052;"Aproksimacka";936739431073865789;"TextMESSAGE";"{""text"": ""Buy our NFT today!"", ""files"": [""C:/Users/david/Downloads/display.jpg""]}";"send";"{""successful"": [{""name"": ""test"", ""id"": 1159224699830677685}, {""name"": ""test-general"", ""id"": 1199770792695705732}], ""failed"": []}";"" 2 | 436766314447364;"24.01.2024 18:46:55";"GUILD";"zajcek's dungeon";863071397207212052;"Aproksimacka";936739431073865789;"TextMESSAGE";"{""text"": ""Buy our NFT today!"", ""files"": [""C:/Users/david/Downloads/display.jpg""]}";"send";"{""successful"": [{""name"": ""test"", ""id"": 1159224699830677685}, {""name"": ""test-general"", ""id"": 1199770792695705732}], ""failed"": []}";"" 3 | 436766318421509;"24.01.2024 18:47:11";"GUILD";"zajcek's dungeon";863071397207212052;"Aproksimacka";936739431073865789;"TextMESSAGE";"{""text"": ""Buy our NFT today!"", ""files"": [""C:/Users/david/Downloads/display.jpg""]}";"send";"{""successful"": [{""name"": ""test"", ""id"": 1159224699830677685}, {""name"": ""test-general"", ""id"": 1199770792695705732}], ""failed"": []}";"" 4 | 436766322161414;"24.01.2024 18:47:25";"GUILD";"zajcek's dungeon";863071397207212052;"Aproksimacka";936739431073865789;"TextMESSAGE";"{""text"": ""Buy our NFT today!"", ""files"": [""C:/Users/david/Downloads/display.jpg""]}";"send";"{""successful"": [{""name"": ""test"", ""id"": 1159224699830677685}, {""name"": ""test-general"", ""id"": 1199770792695705732}], ""failed"": []}";"" 5 | 436766326037255;"24.01.2024 18:47:41";"GUILD";"zajcek's dungeon";863071397207212052;"Aproksimacka";936739431073865789;"TextMESSAGE";"{""text"": ""Buy our NFT today!"", ""files"": [""C:/Users/david/Downloads/display.jpg""]}";"send";"{""successful"": [{""name"": ""test"", ""id"": 1159224699830677685}, {""name"": ""test-general"", ""id"": 1199770792695705732}], ""failed"": []}";"" 6 | -------------------------------------------------------------------------------- /Examples/Logging/CSV/main_csv_logging.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Automatically generated file for Discord Advertisement Framework 4.0.0. 4 | This can be run eg. 24/7 on a server without graphical interface. 5 | 6 | The file has the required classes and functions imported, then the logger is defined and the 7 | accounts list is defined. 8 | 9 | At the bottom of the file the framework is then started with the run function. 10 | """ 11 | 12 | # Import the necessary items 13 | from daf.logging.logger_csv import LoggerCSV 14 | 15 | from daf.messagedata.textdata import TextMessageData 16 | from daf.message.text_based import TextMESSAGE 17 | from daf.client import ACCOUNT 18 | from daf.messagedata import FILE import FILE 19 | from daf.message.messageperiod import FixedDurationPeriod 20 | from datetime import timedelta 21 | from daf.guild.guilduser import GUILD 22 | from daf.logging.tracing import TraceLEVELS 23 | import daf 24 | 25 | # Define the logger 26 | logger = LoggerCSV( 27 | path="C:\\Users\\david\\daf\\History", 28 | delimiter=";", 29 | ) 30 | 31 | # Define remote control context 32 | 33 | 34 | # Defined accounts 35 | accounts = [ 36 | ACCOUNT( 37 | token="TOKEN_HERE", 38 | is_user=True, 39 | servers=[ 40 | GUILD( 41 | snowflake=7312638712639321321, 42 | messages=[ 43 | TextMESSAGE( 44 | data=TextMessageData( 45 | content="Buy our NFT today!", 46 | files=[ 47 | FILE( 48 | filename="C:/Users/david/Downloads/display.jpg", 49 | ), 50 | ], 51 | ), 52 | channels=[ 53 | 1159224699830677685, 54 | 1199770792695705732, 55 | ], 56 | period=FixedDurationPeriod( 57 | duration=timedelta( 58 | seconds=15.0, 59 | minutes=0.0, 60 | ), 61 | ), 62 | ), 63 | ], 64 | logging=True, 65 | ), 66 | ], 67 | ), 68 | ] 69 | 70 | # Run the framework (blocking) 71 | daf.run( 72 | accounts=accounts, 73 | logger=logger, 74 | debug=TraceLEVELS.NORMAL, 75 | save_to_file=False 76 | ) 77 | -------------------------------------------------------------------------------- /Examples/Logging/JSON/History/2023/10/09/zajcek's dungeon1.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zajcek's dungeon", 3 | "id": 863071397207212052, 4 | "type": "GUILD", 5 | "invite_tracking": {}, 6 | "message_tracking": { 7 | "936739431073865789": { 8 | "name": "Aproksimacka", 9 | "id": 936739431073865789, 10 | "messages": [] 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Examples/Logging/JSON/History/2023/12/02/zajcek's dungeon.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zajcek's dungeon", 3 | "id": 863071397207212052, 4 | "type": "GUILD", 5 | "invite_tracking": {}, 6 | "message_tracking": { 7 | "936739431073865789": { 8 | "name": "Aproksimacka", 9 | "id": 936739431073865789, 10 | "messages": [ 11 | { 12 | "sent_data": { 13 | "text": "📣 Boost Your Discord Shilling Game! 🚀\n\nIntroducing the Ultimate Advertising Framework:\n\n✅ Automate Periodic Messages\n✅ Error Checking & Recovery\n✅ Message Logging & Stats\n✅ Multi-Account Support\n✅ GUI / Console Interface\n✅ Easy Setup & Programmatic Usage\n\nGet it now on GitHub: 👉 [https://github.com/davidhozic/discord-advertisement-framework]\n\nFull Documentation: 📚 [https://daf.davidhozic.com/en/v2.10.x/]\n\nUnleash the Power of Shilling Today! 💪\n\n#DiscordAdvertising #ShillingFramework #AutomateYourAds" 14 | }, 15 | "channels": { 16 | "successful": [ 17 | { 18 | "name": "test", 19 | "id": 1159224699830677685 20 | } 21 | ], 22 | "failed": [] 23 | }, 24 | "type": "TextMESSAGE", 25 | "mode": "send", 26 | "index": 435588272653568, 27 | "timestamp": "02.12.2023 12:31:30" 28 | } 29 | ] 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Examples/Logging/JSON/History/2024/01/24/zajcek.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zajcek", 3 | "id": 145196308985020416, 4 | "type": "USER", 5 | "invite_tracking": {}, 6 | "message_tracking": { 7 | "936739431073865789": { 8 | "name": "Aproksimacka", 9 | "id": 936739431073865789, 10 | "messages": [ 11 | { 12 | "sent_data": { 13 | "text": "Buy our red dragon NFTs today!", 14 | "files": [ 15 | "C:/Users/david/Downloads/Picture1.png", 16 | "H:/My Drive/PR/okroznice/2023/2023_01_28 - Skiing.md", 17 | "H:/My Drive/PR/okroznice/2023/2023_10_16 - Volitve SSFE.md" 18 | ] 19 | }, 20 | "success_info": { 21 | "success": true 22 | }, 23 | "type": "DirectMESSAGE", 24 | "mode": "send", 25 | "index": 436765914881537, 26 | "timestamp": "24.01.2024 18:20:55" 27 | }, 28 | { 29 | "sent_data": { 30 | "text": "Buy our red dragon NFTs today!", 31 | "files": [ 32 | "C:/Users/david/Downloads/Picture1.png", 33 | "H:/My Drive/PR/okroznice/2023/2023_01_28 - Skiing.md", 34 | "H:/My Drive/PR/okroznice/2023/2023_10_16 - Volitve SSFE.md" 35 | ] 36 | }, 37 | "success_info": { 38 | "success": true 39 | }, 40 | "type": "DirectMESSAGE", 41 | "mode": "send", 42 | "index": 436765913238528, 43 | "timestamp": "24.01.2024 18:20:48" 44 | } 45 | ] 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /Examples/Logging/JSON/main_json_logging.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Automatically generated file for Discord Advertisement Framework 4.0.0. 4 | This can be run eg. 24/7 on a server without graphical interface. 5 | 6 | The file has the required classes and functions imported, then the logger is defined and the 7 | accounts list is defined. 8 | 9 | At the bottom of the file the framework is then started with the run function. 10 | """ 11 | 12 | # Import the necessary items 13 | from daf.logging.logger_json import LoggerJSON 14 | 15 | from daf.messagedata.textdata import TextMessageData 16 | from daf.message.text_based import TextMESSAGE 17 | from daf.client import ACCOUNT 18 | from daf.messagedata import FILE import FILE 19 | from daf.message.messageperiod import FixedDurationPeriod 20 | from datetime import timedelta 21 | from daf.guild.guilduser import GUILD 22 | from daf.logging.tracing import TraceLEVELS 23 | import daf 24 | 25 | # Define the logger 26 | logger = LoggerJSON( 27 | path="C:\\Users\\david\\daf\\History", 28 | ) 29 | 30 | # Defined accounts 31 | accounts = [ 32 | ACCOUNT( 33 | token="TOKEN_HERE", 34 | is_user=True, 35 | servers=[ 36 | GUILD( 37 | snowflake=7312638712639321321, 38 | messages=[ 39 | TextMESSAGE( 40 | data=TextMessageData( 41 | content="Buy our NFT today!", 42 | files=[ 43 | FILE( 44 | filename="C:/Users/david/Downloads/display.jpg", 45 | ), 46 | ], 47 | ), 48 | channels=[ 49 | 1159224699830677685, 50 | 1199770792695705732, 51 | ], 52 | period=FixedDurationPeriod( 53 | duration=timedelta( 54 | seconds=15.0, 55 | minutes=0.0, 56 | ), 57 | ), 58 | ), 59 | ], 60 | logging=True, 61 | ), 62 | ], 63 | ), 64 | ] 65 | 66 | # Run the framework (blocking) 67 | daf.run( 68 | accounts=accounts, 69 | logger=logger, 70 | debug=TraceLEVELS.NORMAL, 71 | save_to_file=False 72 | ) 73 | -------------------------------------------------------------------------------- /Examples/Logging/SQL/main_sql_logging.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Automatically generated file for Discord Advertisement Framework 4.0.0. 4 | This can be run eg. 24/7 on a server without graphical interface. 5 | 6 | The file has the required classes and functions imported, then the logger is defined and the 7 | accounts list is defined. 8 | 9 | At the bottom of the file the framework is then started with the run function. 10 | """ 11 | 12 | # Import the necessary items 13 | from daf.logging.sql.mgr import LoggerSQL 14 | from daf.messagedata.textdata import TextMessageData 15 | from daf.message.text_based import TextMESSAGE 16 | from daf.client import ACCOUNT 17 | from daf.messagedata import FILE import FILE 18 | from daf.message.messageperiod import FixedDurationPeriod 19 | from datetime import timedelta 20 | from daf.guild.guilduser import GUILD 21 | from daf.logging.tracing import TraceLEVELS 22 | import daf 23 | 24 | # Define the logger 25 | logger = LoggerSQL( 26 | database="C:\\Users\\david\\daf\\messages", 27 | dialect="sqlite", 28 | ) 29 | 30 | # Defined accounts 31 | accounts = [ 32 | ACCOUNT( 33 | token="TOKEN_HERE", 34 | is_user=True, 35 | servers=[ 36 | GUILD( 37 | snowflake=12345678909867, 38 | messages=[ 39 | TextMESSAGE( 40 | data=TextMessageData( 41 | content="Buy our NFT today!", 42 | files=[ 43 | FILE(filename="C:/Users/david/Downloads/display.jpg"), 44 | ], 45 | ), 46 | channels=[ 47 | 123124124123123456789, 48 | 123123123123212345678, 49 | ], 50 | period=FixedDurationPeriod( 51 | duration=timedelta( 52 | minutes=5.0, 53 | ), 54 | ), 55 | ), 56 | ], 57 | logging=True, 58 | invite_track=[ 59 | "F513FF", 60 | "HHSDADSG", 61 | ], 62 | ), 63 | ], 64 | ), 65 | ] 66 | 67 | # Run the framework (blocking) 68 | daf.run( 69 | accounts=accounts, 70 | logger=logger, 71 | debug=TraceLEVELS.NORMAL, 72 | save_to_file=False 73 | ) 74 | -------------------------------------------------------------------------------- /Examples/MessageTypes/TextMESSAGE/main_send_multiple.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Example shows the basic message shilling into a fixed guild. 4 | A text message is sent every 8-12 hours (randomly chosen) and it contains a text content and 3 files. 5 | The message will be first sent in 4 hours. 6 | """ 7 | 8 | # Import the necessary items 9 | from daf.logging.logger_json import LoggerJSON 10 | 11 | from daf.messagedata import FILE 12 | from daf.messagedata.textdata import TextMessageData 13 | from datetime import timedelta 14 | from daf.client import ACCOUNT 15 | from daf.message.text_based import TextMESSAGE 16 | from daf.message.messageperiod import RandomizedDurationPeriod 17 | from daf.guild.guilduser import GUILD 18 | from daf.logging.tracing import TraceLEVELS 19 | import daf 20 | 21 | # Define the logger 22 | logger = LoggerJSON( 23 | path="C:\\Users\\david\\daf\\History", 24 | ) 25 | 26 | 27 | # Defined accounts 28 | accounts = [ 29 | ACCOUNT( 30 | token="TOKEN", 31 | is_user=True, 32 | servers=[ 33 | GUILD( 34 | snowflake=123456789, 35 | messages=[ 36 | TextMESSAGE( 37 | data=TextMessageData( 38 | content="Buy our red dragon NFTs today!", 39 | files=[ 40 | FILE(filename="C:/Users/david/Downloads/Picture1.png"), 41 | FILE(filename="H:/My Drive/PR/okroznice/2023/2023_01_28 - Skiing.md"), 42 | FILE(filename="H:/My Drive/PR/okroznice/2023/2023_10_16 - Volitve SSFE.md"), 43 | ], 44 | ), 45 | channels=[123123231232131231, 329312381290381208321, 3232320381208321], 46 | period=RandomizedDurationPeriod( 47 | minimum=timedelta(hours=8.0), 48 | maximum=timedelta(hours=12.0), 49 | next_send_time=timedelta(hours=4.0), 50 | ), 51 | ), 52 | ], 53 | logging=True, 54 | ), 55 | ], 56 | ), 57 | ] 58 | 59 | # Run the framework (blocking) 60 | daf.run( 61 | accounts=accounts, 62 | logger=logger, 63 | debug=TraceLEVELS.NORMAL, 64 | ) 65 | -------------------------------------------------------------------------------- /Examples/MessageTypes/VoiceMESSAGE/VoiceMessage.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/Examples/MessageTypes/VoiceMESSAGE/VoiceMessage.mp3 -------------------------------------------------------------------------------- /Examples/MessageTypes/VoiceMESSAGE/main_send.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Example shows the basic message shilling into a fixed guild. 4 | A text message is sent every 30-90 minutes (randomly chosen) and it plays a single audio file. 5 | The message will be first sent in 10 minutes. 6 | """ 7 | 8 | # Import the necessary items 9 | from daf.logging.logger_json import LoggerJSON 10 | 11 | from daf.messagedata import FILE 12 | from daf.messagedata.voicedata import VoiceMessageData 13 | from datetime import timedelta 14 | from daf.client import ACCOUNT 15 | from daf.message.voice_based import VoiceMESSAGE 16 | from daf.message.messageperiod import RandomizedDurationPeriod 17 | from daf.guild.guilduser import GUILD 18 | from daf.logging.tracing import TraceLEVELS 19 | import daf 20 | 21 | # Define the logger 22 | logger = LoggerJSON( 23 | path="C:\\Users\\david\\daf\\History", 24 | ) 25 | 26 | # Defined accounts 27 | accounts = [ 28 | ACCOUNT( 29 | token="TOKEN", 30 | is_user=True, 31 | servers=[ 32 | GUILD( 33 | snowflake=318732816317823168276278, 34 | messages=[ 35 | VoiceMESSAGE( 36 | data=VoiceMessageData(FILE(filename="./VoiceMESSAGE.mp3")), 37 | channels=[1136787403588255784, 1199125280149733449], 38 | period=RandomizedDurationPeriod( 39 | minimum=timedelta(minutes=30), 40 | maximum=timedelta(minutes=90), 41 | next_send_time=timedelta(minutes=10), 42 | ), 43 | ), 44 | ], 45 | logging=True, 46 | ), 47 | ], 48 | ), 49 | ] 50 | 51 | # Run the framework (blocking) 52 | daf.run( 53 | accounts=accounts, 54 | logger=logger, 55 | debug=TraceLEVELS.NORMAL, 56 | ) 57 | -------------------------------------------------------------------------------- /Examples/Web/main_web.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Example shows login with email and password. 4 | The AutoGUILD defines an auto_join parameter, which will be used to (semi) automatically 5 | join new guilds based on a prompt. You as a user still need to solve any CAPTCHA challenges. 6 | """ 7 | 8 | # Import the necessary items 9 | from daf.web import QueryMembers 10 | from daf.client import ACCOUNT 11 | from daf.web import GuildDISCOVERY 12 | from daf.web import QuerySortBy 13 | from daf.guild.autoguild import AutoGUILD 14 | from daf.logging.tracing import TraceLEVELS 15 | import daf 16 | 17 | 18 | # Defined accounts 19 | accounts = [ 20 | ACCOUNT( 21 | servers=[ 22 | AutoGUILD( 23 | include_pattern=".*", 24 | auto_join=GuildDISCOVERY( 25 | prompt="NFT arts", 26 | sort_by=QuerySortBy.TOP, 27 | total_members=QueryMembers.B100_1k, 28 | limit=30, 29 | ), 30 | ), 31 | ], 32 | username="username@email.com", 33 | password="password", 34 | ), 35 | ] 36 | 37 | # Run the framework (blocking) 38 | daf.run( 39 | accounts=accounts, 40 | debug=TraceLEVELS.NORMAL, 41 | ) 42 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | **DAF License** 2 | 3 | MIT License 4 | 5 | Copyright (c) 2022-present David Hozic 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | 25 |


26 | 27 | **PyCord (API Wrapper) License:** 28 | 29 | *Concerns only src/_discord/ folder* 30 |
31 |
32 | 33 | The MIT License (MIT) 34 | 35 | Copyright (c) 2015-2021 Rapptz 36 | Copyright (c) 2021-present Pycord Development 37 | 38 | Permission is hereby granted, free of charge, to any person obtaining a 39 | copy of this software and associated documentation files (the "Software"), 40 | to deal in the Software without restriction, including without limitation 41 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 42 | and/or sell copies of the Software, and to permit persons to whom the 43 | Software is furnished to do so, subject to the following conditions: 44 | 45 | The above copyright notice and this permission notice shall be included in 46 | all copies or substantial portions of the Software. 47 | 48 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 49 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 50 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 51 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 52 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 53 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 54 | DEALINGS IN THE SOFTWARE. 55 | 56 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | include LICENSE.md 3 | include *.txt 4 | include src/_discord/bin/*.dll 5 | -------------------------------------------------------------------------------- /Patches/1_client.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/_discord/client.py b/src/_discord/client.py 2 | index 0be4855..08c6469 100644 3 | --- a/src/_discord/client.py 4 | +++ b/src/_discord/client.py 5 | @@ -482,7 +482,7 @@ class Client: 6 | 7 | # login state management 8 | 9 | - async def login(self, token: str) -> None: 10 | + async def login(self, token: str, bot: bool) -> None: 11 | """|coro| 12 | 13 | Logs in the client with the specified credentials. 14 | @@ -511,7 +511,7 @@ class Client: 15 | 16 | _log.info("logging in using static token") 17 | 18 | - data = await self.http.static_login(token.strip()) 19 | + data = await self.http.static_login(token.strip(), bot) 20 | self._connection.user = ClientUser(state=self._connection, data=data) 21 | 22 | async def connect(self, *, reconnect: bool = True) -> None: 23 | @@ -645,7 +645,7 @@ class Client: 24 | self._connection.clear() 25 | self.http.recreate() 26 | 27 | - async def start(self, token: str, *, reconnect: bool = True) -> None: 28 | + async def start(self, token: str, *, reconnect: bool = True, bot: bool = True) -> None: 29 | """|coro| 30 | 31 | A shorthand coroutine for :meth:`login` + :meth:`connect`. 32 | @@ -655,7 +655,7 @@ class Client: 33 | TypeError 34 | An unexpected keyword argument was received. 35 | """ 36 | - await self.login(token) 37 | + await self.login(token, bot=bot) 38 | await self.connect(reconnect=reconnect) 39 | 40 | def run(self, *args: Any, **kwargs: Any) -> None: 41 | -------------------------------------------------------------------------------- /Patches/4_version.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/_discord/_version.py b/src/_discord/_version.py 2 | index c58c8ba..3761f0f 100644 3 | --- a/src/_discord/_version.py 4 | +++ b/src/_discord/_version.py 5 | @@ -37,25 +37,7 @@ from typing import Literal, NamedTuple 6 | 7 | from .utils import deprecated 8 | 9 | -try: 10 | - __version__ = version("py-cord") 11 | -except PackageNotFoundError: 12 | - # Package is not installed 13 | - try: 14 | - from setuptools_scm import get_version # type: ignore[import] 15 | - 16 | - __version__ = get_version() 17 | - except ImportError: 18 | - # setuptools_scm is not installed 19 | - __version__ = "0.0.0" 20 | - warnings.warn( 21 | - ( 22 | - "Package is not installed, and setuptools_scm is not installed. " 23 | - f"As a fallback, {__name__}.__version__ will be set to {__version__}" 24 | - ), 25 | - RuntimeWarning, 26 | - stacklevel=2, 27 | - ) 28 | +__version__ = "2.4.1" 29 | 30 | 31 | class AdvancedVersionInfo(TypedDict): 32 | -------------------------------------------------------------------------------- /Patches/5_interactions.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/_discord/interactions.py b/src/_discord/interactions.py 2 | index 462d613..fcec91a 100644 3 | --- a/src/_discord/interactions.py 4 | +++ b/src/_discord/interactions.py 5 | @@ -154,13 +154,14 @@ class Interaction: 6 | 7 | def _from_data(self, data: InteractionPayload): 8 | self.id: int = int(data["id"]) 9 | - self.type: InteractionType = try_enum(InteractionType, data["type"]) 10 | + self.type: InteractionType = try_enum(InteractionType, data.get("type")) 11 | self.data: InteractionData | None = data.get("data") 12 | - self.token: str = data["token"] 13 | - self.version: int = data["version"] 14 | + self.token: str = data.get("token") 15 | + self.version: int = data.get("version") 16 | self.channel_id: int | None = utils._get_as_snowflake(data, "channel_id") 17 | self.guild_id: int | None = utils._get_as_snowflake(data, "guild_id") 18 | - self.application_id: int = int(data["application_id"]) 19 | + app_id = data.get("application_id") 20 | + self.application_id: int = int(app_id) if app_id is not None else -1 21 | self.locale: str | None = data.get("locale") 22 | self.guild_locale: str | None = data.get("guild_locale") 23 | self.custom_id: str | None = ( 24 | diff --git a/src/_discord/state.py b/src/_discord/state.py 25 | index 6cd46ba..d8cb498 100644 26 | --- a/src/_discord/state.py 27 | +++ b/src/_discord/state.py 28 | @@ -793,14 +793,14 @@ class ConnectionState: 29 | 30 | def parse_interaction_create(self, data) -> None: 31 | interaction = Interaction(data=data, state=self) 32 | - if data["type"] == 3: # interaction component 33 | - custom_id = interaction.data["custom_id"] # type: ignore 34 | - component_type = interaction.data["component_type"] # type: ignore 35 | + if data.get("type") == 3: # interaction component 36 | + custom_id = interaction.data.get("custom_id") # type: ignore 37 | + component_type = interaction.data.get("component_type") # type: ignore 38 | self._view_store.dispatch(component_type, custom_id, interaction) 39 | if interaction.type == InteractionType.modal_submit: 40 | user_id, custom_id = ( 41 | interaction.user.id, 42 | - interaction.data["custom_id"], 43 | + interaction.data.get("custom_id"), 44 | ) 45 | asyncio.create_task( 46 | self._modal_store.dispatch(user_id, custom_id, interaction) 47 | -------------------------------------------------------------------------------- /Patches/6_embeds.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/_discord/embeds.py b/src/_discord/embeds.py 2 | index 44d51e8..7633330 100644 3 | --- a/src/_discord/embeds.py 4 | +++ b/src/_discord/embeds.py 5 | @@ -28,6 +28,9 @@ from __future__ import annotations 6 | import datetime 7 | from typing import TYPE_CHECKING, Any, Mapping, TypeVar 8 | 9 | +from _discord.types.embed import EmbedType 10 | + 11 | + 12 | from . import utils 13 | from .colour import Colour 14 | 15 | @@ -45,7 +48,6 @@ E = TypeVar("E", bound="Embed") 16 | 17 | if TYPE_CHECKING: 18 | from _discord.types.embed import Embed as EmbedData 19 | - from _discord.types.embed import EmbedType 20 | 21 | 22 | class EmbedAuthor: 23 | -------------------------------------------------------------------------------- /Patches/7_state.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/_discord/state.py b/src/_discord/state.py 2 | index 13cbf61..94893b2 100644 3 | --- a/src/_discord/state.py 4 | +++ b/src/_discord/state.py 5 | @@ -1141,7 +1141,17 @@ class ConnectionState: 6 | self.dispatch("member_join", member) 7 | 8 | def parse_guild_member_remove(self, data) -> None: 9 | - user = self.store_user(data["user"]) 10 | + # Check if data contains necessary items 11 | + user_data = data["user"] 12 | + for attr in {"username", "id", "discriminator", "avatar"}: 13 | + if attr not in user_data: 14 | + _log.warning( 15 | + f"Payload does not contain necessary information (Missing {attr}). " 16 | + f"Payload contains: {str(data.keys())}" 17 | + ) 18 | + return 19 | + 20 | + user = self.store_user(user_data) 21 | raw = RawMemberRemoveEvent(data, user) 22 | 23 | guild = self._get_guild(int(data["guild_id"])) 24 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ========================================================= 2 | Discord Advertisement Framework 3 | ========================================================= 4 | The Discord advertisement framework is a Python based automatic application that allows **easy periodic advertisement** / **shilling** on Discord. 5 | 6 | 7 | .. image:: ./docs/images/daf-gui-front.png 8 | 9 | .. image:: ./docs/images/daf-gui-front-edit-msg.png 10 | 11 | ---------------- 12 | Guide / Usage 13 | ---------------- 14 | Instructions can be found `here `_. 15 | 16 | --------------- 17 | Help 18 | --------------- 19 | Need help? Contact me in my `Discord server `_. 20 | 21 | ---------------------- 22 | Key features 23 | ---------------------- 24 | - Automatic periodic and scheduled messages to multiple servers and channels, 25 | - Error checking and recovery, 26 | - Message logging, invite link tracking & statistics 27 | - Multi-account support 28 | - Graphical Interface (GUI) / Console (script) 29 | - Easy to setup 30 | - Much more 31 | 32 | ---------------------- 33 | Installation 34 | ---------------------- 35 | DAF can be installed though command prompt/terminal using the bottom commands. 36 | 37 | Pre-requirement: `Python (minimum v3.9 and currently max 3.11; 3.12 support is pending) `_. 38 | 39 | **Main package** 40 | 41 | :: 42 | 43 | pip install discord-advert-framework 44 | 45 | **Voice Messaging / AUDIO** 46 | 47 | :: 48 | 49 | pip install discord-advert-framework[voice] 50 | 51 | 52 | **SQL logging** 53 | 54 | :: 55 | 56 | pip install discord-advert-framework[sql] 57 | 58 | 59 | **Chrome browser integration** 60 | 61 | :: 62 | 63 | pip install discord-advert-framework[web] 64 | 65 | **All of the above (full package)** 66 | 67 | :: 68 | 69 | pip install discord-advert-framework[all] 70 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR ?= source 9 | BUILDDIR ?= build 10 | USE_LANGUAGE ?= sl 11 | 12 | export LANGUAGE=$(USE_LANGUAGE) 13 | 14 | _BUILD_DIR = $(BUILDDIR)/$(SOURCEDIR) 15 | 16 | # OS specific commands 17 | ifeq ($(OS), Windows_NT) 18 | LATEX_CMD := \ 19 | cp $(CURDIR)/build-latex-win.sh $(CURDIR)/$(_BUILD_DIR)/latex/ &&\ 20 | wsl --cd $(CURDIR)/$(_BUILD_DIR)/latex sh build-latex-win.sh 21 | 22 | else 23 | LATEX_CMD := cd $(CURDIR)/$(_BUILD_DIR)/latex && make all-pdf 24 | endif 25 | 26 | 27 | # Put it first so that "make" without argument is like "make help". 28 | help: 29 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 30 | 31 | .PHONY: help Makefile 32 | 33 | # Catch-all target: route all unknown targets to Sphinx using the new 34 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 35 | 36 | clean: 37 | python ./setup.py --clean --start-dir $(SOURCEDIR) 38 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(_BUILD_DIR)" $(SPHINXOPTS) $(O) 39 | 40 | pdf: latex 41 | mkdir -p $(CURDIR)/$(_BUILD_DIR)/pdf/ 42 | $(LATEX_CMD) 43 | cp $(CURDIR)/$(_BUILD_DIR)/latex/*.pdf $(CURDIR)/$(_BUILD_DIR)/pdf/ 44 | 45 | %: Makefile 46 | python3 ./setup.py --start-dir $(SOURCEDIR) 47 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(_BUILD_DIR)" $(SPHINXOPTS) $(O) 48 | -------------------------------------------------------------------------------- /docs/build-latex-win.sh: -------------------------------------------------------------------------------- 1 | # Script is created to speed up the latex compilation on the windows system though wsl. 2 | # It copis all latex files to a wsl directory, runs the latex compiler and then copies them back 3 | # to the orignal path. 4 | 5 | ORIGIN_DIR=$(pwd) 6 | LATEX_BUILD_PATH=~/latex-build/ 7 | 8 | # Copy the current folder (latex build folder) contents to our home folder 9 | echo Creating dir $LATEX_BUILD_PATH 10 | mkdir -p $LATEX_BUILD_PATH 11 | 12 | echo Copying files to $LATEX_BUILD_PATH 13 | cp -r $ORIGIN_DIR/** $LATEX_BUILD_PATH 14 | 15 | echo Building latex 16 | cd $LATEX_BUILD_PATH 17 | make all-pdf 18 | cp -r $LATEX_BUILD_PATH/** $ORIGIN_DIR 19 | 20 | echo Cleaning up $LATEX_BUILD_PATH 21 | rm -rf $LATEX_BUILD_PATH 22 | -------------------------------------------------------------------------------- /docs/dep_local.json: -------------------------------------------------------------------------------- 1 | { 2 | "copy": [], 3 | "scripts": [] 4 | } -------------------------------------------------------------------------------- /docs/images/daf-console-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/images/daf-console-run.png -------------------------------------------------------------------------------- /docs/images/daf-gui-front-edit-msg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/images/daf-gui-front-edit-msg.png -------------------------------------------------------------------------------- /docs/images/daf-gui-front.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/images/daf-gui-front.png -------------------------------------------------------------------------------- /docs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/images/logo.png -------------------------------------------------------------------------------- /docs/source/dep_local.json: -------------------------------------------------------------------------------- 1 | { 2 | "copy": [ 3 | {"from": "../images/*", "to": "./DEP/"}, 4 | {"from": "../../Examples/**", "to":"./DEP/"} 5 | ], 6 | "scripts": ["./scripts/generate_autodoc.py"] 7 | } -------------------------------------------------------------------------------- /docs/source/guide/GUI/control.rst: -------------------------------------------------------------------------------- 1 | ======================= 2 | Framework control (GUI) 3 | ======================= 4 | 5 | Run control 6 | ------------- 7 | The framework can be from the GUI controlled with the 2 buttons located on the top left corner of the GUI. 8 | 9 | These buttons are called **START** and **STOP** respectively. 10 | 11 | .. image:: images/gui-start-stop-bnt.png 12 | :align: center 13 | 14 | 15 | **Start** button will, like the name suggest, start the framework (or connect to a remote server, see :ref:`Remote control (GUI)`). 16 | If the **Load all at start** checkbox inside *Schema definition* tab, Accounts frame, is checked, it will also load all of the 17 | defined account templates into DAF. Additionally the selected logger inside the Logging frame is set to be used to log messages 18 | and invites links and it cannot be changed unless the framework is restarted (the same goes for remote). 19 | 20 | Inside the *Output* tab, the core's output can be viewed reporting any runtime errors. 21 | 22 | .. image:: images/gui-started-output-defined-accounts.png 23 | :align: center 24 | -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/edit-remoteconnectionclient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/edit-remoteconnectionclient.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-analytics-invite-frame-get-logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-analytics-invite-frame-get-logs.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-analytics-invite-frame-view-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-analytics-invite-frame-view-log.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-analytics-invite-frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-analytics-invite-frame.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-analytics-message-frame-get-logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-analytics-message-frame-get-logs.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-analytics-message-frame-view-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-analytics-message-frame-view-log.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-analytics-message-frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-analytics-message-frame.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-analytics-num-invite-frame-calc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-analytics-num-invite-frame-calc.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-analytics-num-invite-frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-analytics-num-invite-frame.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-analytics-num-message-frame-calc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-analytics-num-message-frame-calc.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-analytics-num-message-frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-analytics-num-message-frame.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-analytics-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-analytics-tab.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-connection-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-connection-select.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-defined-accounts-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-defined-accounts-list.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-depend-install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-depend-install.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-live-view-add-object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-live-view-add-object.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-live-view-autochannel-view-property-channels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-live-view-autochannel-view-property-channels.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-live-view-edit-account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-live-view-edit-account.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-live-view-property-view-autochannel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-live-view-property-view-autochannel.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-live-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-live-view.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-load-accounts-bnts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-load-accounts-bnts.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-logger-definition-edit-json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-logger-definition-edit-json.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-logger-definition-tracing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-logger-definition-tracing.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-messages-sent-post-acc-definition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-messages-sent-post-acc-definition.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-new-account-window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-new-account-window.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-new-item-define-string-window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-new-item-define-string-window.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-new-item-define.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-new-item-define.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-new-item-edit-string-window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-new-item-edit-string-window.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-new-item-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-new-item-edit.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-new-server-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-new-server-list.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-predefined-value-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-predefined-value-select.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-schema-backup-bnt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-schema-backup-bnt.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-schema-backup-file-save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-schema-backup-file-save.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-schema-restore-bnt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-schema-restore-bnt.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-shill-script-gen-bnt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-shill-script-gen-bnt.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-start-stop-bnt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-start-stop-bnt.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/gui-started-output-defined-accounts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/gui-started-output-defined-accounts.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/new-account-template-bnt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/new-account-template-bnt.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/open-logger-definition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/open-logger-definition.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/images/run-windows-daf-gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/GUI/images/run-windows-daf-gui.png -------------------------------------------------------------------------------- /docs/source/guide/GUI/index.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | Guide (GUI) 3 | ================== 4 | This section contains the guide to using the Discord Advertisement Framework inside a **G**\ raphical **U**\ ser **I**\ nterface. 5 | 6 | .. toctree:: 7 | 8 | 9 | quickstart 10 | control 11 | schema 12 | live_view 13 | filegen 14 | analytics 15 | remote 16 | -------------------------------------------------------------------------------- /docs/source/guide/GUI/live_view.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | Live view (GUI) 3 | ========================== 4 | 5 | While the Schema tab allows user to pre-define a schema, the GUI also has a section called *Live view*. 6 | 7 | .. figure:: ./images/gui-live-view.png 8 | :align: center 9 | :width: 20cm 10 | 11 | Live view tab 12 | 13 | 14 | Live view allows users to view and update objects that are currently loaded into the framework. 15 | It allows users to modify the original object parameters and then reinitialize the object to use those same 16 | parameters. This can be done by clicking on the **Update** button. Next to the *Update* button, there is a 17 | **Refresh** button which will reload the GUI with updated values. 18 | If an object does not have a *Update* button, that means the object is not directly supported for live modifications. 19 | In the latter case, users must click the *Save* button, until edit for an object, which supports 20 | live update, is found. **Clicking on Save does not reflect changes in the actual framework**, but just in the currently 21 | opened window. 22 | 23 | When editing / viewing a live object, there is also a **View property** menu button, which allows users to inspect 24 | additional object properties of the object running inside DAF. This can eg. be used to view the channels, that 25 | were found using :class:`~daf.message.AutoCHANNEL` object. 26 | 27 | 28 | .. image:: images/gui-live-view-property-view-autochannel.png 29 | 30 | .. image:: images/gui-live-view-autochannel-view-property-channels.png 31 | 32 | 33 | Some live objects like :class:`~daf.client.ACCOUNT` also support **method execution**, where you can eg. add or remove 34 | servers without updating the entire object. 35 | 36 | .. image:: ./images/gui-live-view-edit-account.png 37 | :align: center 38 | 39 | 40 | At the top of the *Live view* tab, there's also an *Execute* button with a dropdown menu. It allows you to define a new 41 | :class:`~daf.client.ACCOUNT` object by clicking *Edit* and load the object into the framework directly. 42 | However it is recommended that accounts are defined inside the :ref:`Account definition / schema tab (GUI)` and loaded by clicking the 43 | *Load selection to live* button (see :ref:`Loading schema into DAF (GUI)`). 44 | 45 | .. image:: ./images/gui-live-view-add-object.png 46 | :align: center 47 | :width: 20cm 48 | -------------------------------------------------------------------------------- /docs/source/guide/GUI/remote.rst: -------------------------------------------------------------------------------- 1 | ====================== 2 | Remote control (GUI) 3 | ====================== 4 | .. versionadded:: 2.8 5 | 6 | 7 | .. seealso:: 8 | 9 | This section describes how to set up the GUI to connect to a server. 10 | To find information about setting up the actual server see :ref:`Remote control (core)`. 11 | 12 | 13 | DAF can run either locally or it can connect to a remote server that is running the 14 | DAF core. Users can choose between these two options by changing the connection client as 15 | shown in picture: 16 | 17 | .. image:: ./images/gui-connection-select.png 18 | :width: 1000px 19 | 20 | Using ``LocalConnectionCLIENT`` will start DAF locally and anything the users do will be done locally. 21 | Using :class:`~daf_gui.connector.RemoteConnectionCLIENT` will connect to a remote server and anything the users do including adding / removing 22 | accounts, retrieving logs, etc. will be done through a HTTP API which can also be HTTPS (recommended) if desired. 23 | 24 | 25 | If the *Edit* button is clicked (in the top right corner) and :class:`~daf_gui.connector.RemoteConnectionCLIENT` 26 | is selected, a new window will be opened, which allows customization of connection parameters. 27 | 28 | 29 | .. image:: ./images/edit-remoteconnectionclient.png 30 | 31 | .. autoclass:: daf_gui.connector.RemoteConnectionCLIENT 32 | 33 | .. seealso:: 34 | 35 | When :ref:`generating the DAF core script `, 36 | remote access will also be configured if the :class:`~daf_gui.connector.RemoteConnectionCLIENT` is selected. 37 | 38 | Clicking on *Edit* when ``LocalConnectionCLIENT`` is selected will show an error. 39 | -------------------------------------------------------------------------------- /docs/source/guide/core/autogen.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Automatic Generation (core) 3 | ============================ 4 | This documents describes mechanisms that can be used to automatically generate objects. 5 | 6 | --------------------------- 7 | Shilling scheme generation 8 | --------------------------- 9 | While the servers can be manually defined and configured, which can be time consuming if you have a lot of 10 | guilds to shill into, DAF also supports automatic definition of servers and channels. 11 | Servers and channels can be automatically defined by creating some matching rules described in the 12 | :ref:`Matching logic` chapter of this guide. 13 | 14 | 15 | 16 | Automatic GUILD generation 17 | ============================== 18 | 19 | .. seealso:: 20 | This section only describes guilds that the user **is already joined in**. 21 | For information about **discovering NEW guilds and automatically joining them** see 22 | :ref:`Automatic guild discovery and join` 23 | 24 | .. |AUTOGUILD| replace:: :class:`~daf.guild.AutoGUILD` 25 | .. |GUILD| replace:: :class:`~daf.guild.GUILD` 26 | .. |AUTOCHANNEL| replace:: :class:`~daf.message.AutoCHANNEL` 27 | 28 | For a automatically managed servers, use |AUTOGUILD| which internally generates |GUILD| instances. 29 | Simply create a list of |AUTOGUILD| objects and then pass it to the ``servers`` parameter of 30 | :class:`daf.client.ACCOUNT`. 31 | 32 | .. WARNING:: 33 | 34 | Messages that are added to |AUTOGUILD| should have |AUTOCHANNEL| for the ``channels`` parameters, 35 | otherwise you will be spammed with warnings and only one guild will be shilled. 36 | 37 | 38 | .. literalinclude:: ./DEP/Examples/AutomaticGeneration/main_autoguild.py 39 | 40 | 41 | Automatic channel generation 42 | ============================== 43 | For a automatically managed channels, use |AUTOCHANNEL|. 44 | It can be passed to xMESSAGE objects to the ``channels`` parameters. 45 | 46 | .. literalinclude:: ./DEP/Examples/AutomaticGeneration/main_autochannel.py 47 | :caption: AutoCHANNEL example 48 | -------------------------------------------------------------------------------- /docs/source/guide/core/control.rst: -------------------------------------------------------------------------------- 1 | 2 | ========================= 3 | Framework control (core) 4 | ========================= 5 | The following section shows how DAF's core can be started / stopped. 6 | The first thing you need is the library installed, see :ref:`Installation`. 7 | 8 | The framework can be started using :func:`daf.core.run` function and stopped with the :func:`daf.core.shutdown` function. 9 | It can also be stopped by a SIGINT signal, which can be signaled using CTRL+C. 10 | For full list of parameters refer to :func:`daf.core.run`'s description. 11 | 12 | .. code-block:: python 13 | 14 | import daf 15 | daf.run() 16 | 17 | The above code is somewhat useless as nothing was configured. 18 | :ref:`On the next page `, 19 | we will take a look on how to define our accounts, guilds (servers) and messages. 20 | -------------------------------------------------------------------------------- /docs/source/guide/core/images/captcha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/core/images/captcha.png -------------------------------------------------------------------------------- /docs/source/guide/core/images/message_definition_example_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/core/images/message_definition_example_output.png -------------------------------------------------------------------------------- /docs/source/guide/core/images/search_update_method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/core/images/search_update_method.png -------------------------------------------------------------------------------- /docs/source/guide/core/index.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | Guide (core) 3 | ================== 4 | This section contains the guide to using the Discord Advertisement Framework at it's core (console) or in other 5 | words, running it directly by Python and providing all the required information inside a Python script (``.py`` file). 6 | 7 | 8 | .. toctree:: 9 | 10 | control 11 | shilldefine 12 | logging 13 | logic 14 | autogen 15 | autoresponder 16 | web 17 | modification 18 | remote 19 | -------------------------------------------------------------------------------- /docs/source/guide/core/remote.rst: -------------------------------------------------------------------------------- 1 | ====================== 2 | Remote control (core) 3 | ====================== 4 | 5 | .. versionadded:: 2.8 6 | 7 | While DAF can run completely standalone locally, it also allows to be run as a server that will accept connections from 8 | a graphical interface (:ref:`Remote control (GUI)`). 9 | 10 | The remote module spins up a HTTP server, which can also be given a certificate and a private key allowing HTTPS connections. 11 | 12 | To set up the core as a remote server, pass the :func:`~daf.core.run` function with the ``remote_client`` parameter. 13 | It accepts an object of type :class:`daf.remote.RemoteAccessCLIENT`. 14 | 15 | After the script is ran, DAF will listen and accept connections based on the configured options. While the server is running, 16 | DAF can be used the same way as if there was no server at all. 17 | -------------------------------------------------------------------------------- /docs/source/guide/dep_local.json: -------------------------------------------------------------------------------- 1 | { 2 | "copy": [ 3 | {"from": "../../../Examples/", "to":"./core/DEP/"}, 4 | {"from": "../../../Examples/", "to":"./GUI/DEP/"}, 5 | {"from": "../../images/", "to":"./GUI/DEP/"}, 6 | {"from": "../../images/", "to":"./core/DEP/"}, 7 | {"from": "./images/", "to":"./GUI/DEP/"}, 8 | {"from": "./images/", "to":"./core/DEP/"} 9 | ], 10 | "scripts": [] 11 | } -------------------------------------------------------------------------------- /docs/source/guide/images/copy-snowflake-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/images/copy-snowflake-id.png -------------------------------------------------------------------------------- /docs/source/guide/images/daf-console-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/guide/images/daf-console-run.png -------------------------------------------------------------------------------- /docs/source/guide/index.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | Guide 3 | ================== 4 | 5 | 6 | The following pages contain guides to running the Discord Advertisement Framework in 2 main modes: 7 | 8 | 1. :ref:`Core mode (console / programming) ` 9 | 2. :ref:`Graphical mode (GUI) ` 10 | 11 | .. toctree:: 12 | 13 | GUI/index 14 | core/index 15 | 16 | -------------------------------------------------------------------------------- /docs/source/images/changelog_2_1_slippage_fix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/source/images/changelog_2_1_slippage_fix.png -------------------------------------------------------------------------------- /docs/thesis/ExampleUsage/example-autoguild-autochannel.json: -------------------------------------------------------------------------------- 1 | { 2 | "loggers": { 3 | "all": [ 4 | { 5 | "type": "daf.logging._logging.LoggerJSON", 6 | "data": { 7 | "path": "C:\\Users\\David\\daf\\History" 8 | } 9 | }, 10 | { 11 | "type": "daf.logging.sql.mgr.LoggerSQL", 12 | "data": { 13 | "database": "C:\\Users\\David\\daf\\messages", 14 | "dialect": "sqlite" 15 | } 16 | }, 17 | { 18 | "type": "daf.logging._logging.LoggerCSV", 19 | "data": { 20 | "path": "C:\\Users\\David\\daf\\History", 21 | "delimiter": ";" 22 | } 23 | } 24 | ], 25 | "selected_index": 0 26 | }, 27 | "tracing": 3, 28 | "accounts": [ 29 | { 30 | "type": "daf.client.ACCOUNT", 31 | "data": { 32 | "token": "OTMHH72GFA7213JSDH2131HJb", 33 | "is_user": true, 34 | "servers": [ 35 | { 36 | "type": "daf.guild.AutoGUILD", 37 | "data": { 38 | "include_pattern": ".*", 39 | "exclude_pattern": "David's Dungeon", 40 | "messages": [ 41 | { 42 | "type": "daf.message.text_based.TextMESSAGE", 43 | "data": { 44 | "start_period": null, 45 | "end_period": { 46 | "type": "datetime.timedelta", 47 | "data": { 48 | "hours": 2.0 49 | } 50 | }, 51 | "data": [ 52 | "We are excited to announce the launch of our White Rabbit NFT project!" 53 | ], 54 | "channels": { 55 | "type": "daf.message.base.AutoCHANNEL", 56 | "data": { 57 | "include_pattern": "shill|advert|promo|projects", 58 | "exclude_pattern": "vanilla-projects|ssfe-obvestila" 59 | } 60 | } 61 | } 62 | } 63 | ], 64 | "logging": true 65 | } 66 | } 67 | ] 68 | } 69 | } 70 | ], 71 | "connection": { 72 | "all": [ 73 | { 74 | "type": "daf_gui.connector.LocalConnectionCLIENT", 75 | "data": {} 76 | }, 77 | { 78 | "type": "daf_gui.connector.RemoteConnectionCLIENT", 79 | "data": { 80 | "host": "http://" 81 | } 82 | } 83 | ], 84 | "selected_index": 0 85 | } 86 | } -------------------------------------------------------------------------------- /docs/thesis/ExampleUsage/example-autoguild-autochannel.py: -------------------------------------------------------------------------------- 1 | # Import the necessary items 2 | from daf.logging._logging import LoggerJSON 3 | 4 | from daf.message.text_based import TextMESSAGE 5 | from daf.guild import AutoGUILD 6 | from daf.message.base import AutoCHANNEL 7 | from datetime import timedelta 8 | from daf.client import ACCOUNT 9 | from daf.logging.tracing import TraceLEVELS 10 | import daf 11 | 12 | # Define the logger 13 | logger = LoggerJSON( 14 | path="C:\\Users\\David\\daf\\History", 15 | ) 16 | 17 | # Define remote control context 18 | 19 | 20 | # Defined accounts 21 | accounts = [ 22 | ACCOUNT( 23 | token="OTMHH72GFA7213JSDH2131HJb", 24 | is_user=True, 25 | servers=[ 26 | AutoGUILD( 27 | include_pattern=".*", 28 | exclude_pattern="David's Dungeon", 29 | messages=[ 30 | TextMESSAGE( 31 | start_period=None, 32 | end_period=timedelta( 33 | hours=2.0, 34 | ), 35 | data=[ 36 | "We are excited to announce...!", 37 | ], 38 | channels=AutoCHANNEL( 39 | include_pattern="shill|advert|promo|projects", 40 | exclude_pattern="vanilla-projects|ssfe-obvestila", 41 | ), 42 | ), 43 | ], 44 | logging=True, 45 | ), 46 | ], 47 | ), 48 | ] 49 | 50 | # Run the framework (blocking) 51 | daf.run( 52 | accounts=accounts, 53 | logger=logger, 54 | debug=TraceLEVELS.NORMAL, 55 | save_to_file=False 56 | ) 57 | -------------------------------------------------------------------------------- /docs/thesis/ExampleUsage/example-invites-tracking.json: -------------------------------------------------------------------------------- 1 | { 2 | "loggers": { 3 | "all": [ 4 | { 5 | "type": "daf.logging._logging.LoggerJSON", 6 | "data": { 7 | "path": "C:\\Users\\David\\daf\\History" 8 | } 9 | }, 10 | { 11 | "type": "daf.logging.sql.mgr.LoggerSQL", 12 | "data": { 13 | "database": "C:\\Users\\David\\daf\\messages", 14 | "dialect": "sqlite" 15 | } 16 | }, 17 | { 18 | "type": "daf.logging._logging.LoggerCSV", 19 | "data": { 20 | "path": "C:\\Users\\David\\daf\\History", 21 | "delimiter": ";" 22 | } 23 | } 24 | ], 25 | "selected_index": 0 26 | }, 27 | "tracing": 3, 28 | "accounts": [ 29 | { 30 | "type": "daf.client.ACCOUNT", 31 | "data": { 32 | "token": "OTMHH72GFA7213JSDH2131HJb", 33 | "is_user": true, 34 | "servers": [ 35 | { 36 | "type": "daf.guild.AutoGUILD", 37 | "data": { 38 | "include_pattern": ".*", 39 | "exclude_pattern": "David's Dungeon", 40 | "logging": true, 41 | "invite_track": [ 42 | "PQskxHzgsq", 43 | "8u6kp7NmqK", 44 | "ZE4bgRD2Um" 45 | ] 46 | } 47 | } 48 | ] 49 | } 50 | } 51 | ], 52 | "connection": { 53 | "all": [ 54 | { 55 | "type": "daf_gui.connector.LocalConnectionCLIENT", 56 | "data": {} 57 | }, 58 | { 59 | "type": "daf_gui.connector.RemoteConnectionCLIENT", 60 | "data": { 61 | "host": "http://" 62 | } 63 | } 64 | ], 65 | "selected_index": 0 66 | } 67 | } -------------------------------------------------------------------------------- /docs/thesis/ExampleUsage/example-invites-tracking.py: -------------------------------------------------------------------------------- 1 | # Import the necessary items 2 | from daf.logging._logging import LoggerJSON 3 | 4 | from daf.guild import AutoGUILD 5 | from daf.client import ACCOUNT 6 | from daf.logging.tracing import TraceLEVELS 7 | import daf 8 | 9 | # Define the logger 10 | logger = LoggerJSON( 11 | path="C:\\Users\\David\\daf\\History", 12 | ) 13 | 14 | # Define remote control context 15 | 16 | 17 | # Defined accounts 18 | accounts = [ 19 | ACCOUNT( 20 | token="OTMHH72GFA7213JSDH2131HJb", 21 | is_user=True, 22 | servers=[ 23 | AutoGUILD( 24 | include_pattern=".*", 25 | exclude_pattern="David's Dungeon", 26 | logging=True, 27 | invite_track=[ 28 | "PQskxHzgsq", 29 | "8u6kp7NmqK", 30 | "ZE4bgRD2Um", 31 | ], 32 | ), 33 | ], 34 | ), 35 | ] 36 | 37 | # Run the framework (blocking) 38 | daf.run( 39 | accounts=accounts, 40 | logger=logger, 41 | debug=TraceLEVELS.NORMAL, 42 | save_to_file=False 43 | ) 44 | -------------------------------------------------------------------------------- /docs/thesis/ExampleUsage/example-new-guild-join.json: -------------------------------------------------------------------------------- 1 | { 2 | "loggers": { 3 | "all": [ 4 | { 5 | "type": "daf.logging._logging.LoggerJSON", 6 | "data": { 7 | "path": "C:\\Users\\David\\daf\\History" 8 | } 9 | }, 10 | { 11 | "type": "daf.logging.sql.mgr.LoggerSQL", 12 | "data": { 13 | "database": "C:\\Users\\David\\daf\\messages", 14 | "dialect": "sqlite" 15 | } 16 | }, 17 | { 18 | "type": "daf.logging._logging.LoggerCSV", 19 | "data": { 20 | "path": "C:\\Users\\David\\daf\\History", 21 | "delimiter": ";" 22 | } 23 | } 24 | ], 25 | "selected_index": 0 26 | }, 27 | "tracing": 3, 28 | "accounts": [ 29 | { 30 | "type": "daf.client.ACCOUNT", 31 | "data": { 32 | "servers": [ 33 | { 34 | "type": "daf.guild.AutoGUILD", 35 | "data": { 36 | "include_pattern": ".*", 37 | "auto_join": { 38 | "type": "daf.web.GuildDISCOVERY", 39 | "data": { 40 | "prompt": "NFT", 41 | "sort_by": { 42 | "type": "daf.web.QuerySortBy", 43 | "value": 0 44 | }, 45 | "total_members": { 46 | "type": "daf.web.QueryMembers", 47 | "value": 2 48 | }, 49 | "limit": 15 50 | } 51 | } 52 | } 53 | } 54 | ], 55 | "username": "ime.priimerk", 56 | "password": "geslo.moje" 57 | } 58 | } 59 | ], 60 | "connection": { 61 | "all": [ 62 | { 63 | "type": "daf_gui.connector.LocalConnectionCLIENT", 64 | "data": {} 65 | }, 66 | { 67 | "type": "daf_gui.connector.RemoteConnectionCLIENT", 68 | "data": { 69 | "host": "http://" 70 | } 71 | } 72 | ], 73 | "selected_index": 0 74 | } 75 | } -------------------------------------------------------------------------------- /docs/thesis/ExampleUsage/example-new-guild-join.py: -------------------------------------------------------------------------------- 1 | # Import the necessary items 2 | from daf.logging._logging import LoggerJSON 3 | 4 | from daf.guild import AutoGUILD 5 | from daf.web import QuerySortBy 6 | from daf.web import QueryMembers 7 | from daf.client import ACCOUNT 8 | from daf.web import GuildDISCOVERY 9 | from daf.logging.tracing import TraceLEVELS 10 | import daf 11 | 12 | # Define the logger 13 | logger = LoggerJSON( 14 | path="C:\\Users\\David\\daf\\History", 15 | ) 16 | 17 | # Define remote control context 18 | 19 | 20 | # Defined accounts 21 | accounts = [ 22 | ACCOUNT( 23 | servers=[ 24 | AutoGUILD( 25 | include_pattern=".*", 26 | auto_join=GuildDISCOVERY( 27 | prompt="NFT", 28 | sort_by=QuerySortBy.TEXT_RELEVANCY, 29 | total_members=QueryMembers.B100_1k, 30 | limit=15, 31 | ), 32 | ), 33 | ], 34 | username="ime.priimerk", 35 | password="geslo.moje", 36 | ), 37 | ] 38 | 39 | # Run the framework (blocking) 40 | daf.run( 41 | accounts=accounts, 42 | logger=logger, 43 | debug=TraceLEVELS.NORMAL, 44 | save_to_file=False 45 | ) 46 | -------------------------------------------------------------------------------- /docs/thesis/ExampleUsage/example-remote.json: -------------------------------------------------------------------------------- 1 | { 2 | "loggers": { 3 | "all": [ 4 | { 5 | "type": "daf.logging._logging.LoggerJSON", 6 | "data": { 7 | "path": "C:\\Users\\David\\daf\\History" 8 | } 9 | }, 10 | { 11 | "type": "daf.logging.sql.mgr.LoggerSQL", 12 | "data": { 13 | "database": "C:\\Users\\David\\daf\\messages", 14 | "dialect": "sqlite" 15 | } 16 | }, 17 | { 18 | "type": "daf.logging._logging.LoggerCSV", 19 | "data": { 20 | "path": "C:\\Users\\David\\daf\\History", 21 | "delimiter": ";" 22 | } 23 | } 24 | ], 25 | "selected_index": 0 26 | }, 27 | "tracing": 3, 28 | "accounts": [], 29 | "connection": { 30 | "all": [ 31 | { 32 | "type": "daf_gui.connector.LocalConnectionCLIENT", 33 | "data": {} 34 | }, 35 | { 36 | "type": "daf_gui.connector.RemoteConnectionCLIENT", 37 | "data": { 38 | "host": "https://discord.svet.fe.uni-lj.si", 39 | "username": "ime", 40 | "password": "geslo" 41 | } 42 | } 43 | ], 44 | "selected_index": 1 45 | } 46 | } -------------------------------------------------------------------------------- /docs/thesis/ExampleUsage/example-remote.py: -------------------------------------------------------------------------------- 1 | # Import the necessary items 2 | from daf.logging._logging import LoggerJSON 3 | from daf.remote import RemoteAccessCLIENT 4 | 5 | from daf.logging.tracing import TraceLEVELS 6 | import daf 7 | 8 | # Define the logger 9 | logger = LoggerJSON( 10 | path="C:\\Users\\David\\daf\\History", 11 | ) 12 | 13 | # Define remote control context 14 | remote_client = RemoteAccessCLIENT( 15 | host="0.0.0.0", 16 | port=80, 17 | username="ime", 18 | password="geslo", 19 | ) 20 | 21 | # Defined accounts 22 | accounts = [ 23 | ] 24 | 25 | # Run the framework (blocking) 26 | daf.run( 27 | accounts=accounts, 28 | logger=logger, 29 | debug=TraceLEVELS.NORMAL, 30 | remote_client=remote_client, 31 | save_to_file=False 32 | ) 33 | -------------------------------------------------------------------------------- /docs/thesis/ExampleUsage/example-text-message-randomized-period.py: -------------------------------------------------------------------------------- 1 | 2 | # Import the necessary items 3 | from daf.logging._logging import LoggerJSON 4 | 5 | from daf.message.text_based import TextMESSAGE 6 | from daf.guild import GUILD 7 | from datetime import timedelta 8 | from datetime import datetime 9 | from daf.client import ACCOUNT 10 | from daf.logging.tracing import TraceLEVELS 11 | import daf 12 | 13 | # Define the logger 14 | logger = LoggerJSON( 15 | path="C:\\Users\\David\\daf\\History", 16 | ) 17 | 18 | # Define remote control context 19 | 20 | 21 | # Defined accounts 22 | accounts = [ 23 | ACCOUNT( 24 | token="OTMHH72GFA7213JSDH2131HJb", 25 | is_user=True, 26 | servers=[ 27 | GUILD( 28 | snowflake=123456789, 29 | messages=[ 30 | TextMESSAGE( 31 | start_period=timedelta( 32 | hours=1.0, 33 | ), 34 | end_period=timedelta( 35 | hours=2.0, 36 | ), 37 | data="We are excited to announce the launch of our White Rabbit NFT project!", 38 | channels=[ 39 | 2313213123123123123123123, 40 | 9876652312312431232323277, 41 | ], 42 | start_in=datetime( 43 | year=2023, 44 | month=7, 45 | day=13, 46 | ), 47 | remove_after=5, 48 | ), 49 | ], 50 | ), 51 | ], 52 | ), 53 | ] 54 | 55 | # Run the framework (blocking) 56 | daf.run( 57 | accounts=accounts, 58 | logger=logger, 59 | debug=TraceLEVELS.NORMAL, 60 | save_to_file=False 61 | ) 62 | -------------------------------------------------------------------------------- /docs/thesis/IzjavaOAvtorstvu.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/IzjavaOAvtorstvu.pdf -------------------------------------------------------------------------------- /docs/thesis/NaslovnaStranDiplome.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/NaslovnaStranDiplome.pdf -------------------------------------------------------------------------------- /docs/thesis/daf-thesis.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/daf-thesis.pdf -------------------------------------------------------------------------------- /docs/thesis/dep_local.json: -------------------------------------------------------------------------------- 1 | { 2 | "copy": [ 3 | {"from": "../images/logo.png", "to": "./DEP/"} 4 | ], 5 | "scripts": [] 6 | } -------------------------------------------------------------------------------- /docs/thesis/images/autodoc_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/autodoc_example.png -------------------------------------------------------------------------------- /docs/thesis/images/daf-gui-analytics-tab-rotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/daf-gui-analytics-tab-rotated.png -------------------------------------------------------------------------------- /docs/thesis/images/daf-gui-front-rotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/daf-gui-front-rotated.png -------------------------------------------------------------------------------- /docs/thesis/images/daf-gui-live-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/daf-gui-live-view.png -------------------------------------------------------------------------------- /docs/thesis/images/daf-gui-modules-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/daf-gui-modules-tab.png -------------------------------------------------------------------------------- /docs/thesis/images/daf-gui-output-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/daf-gui-output-tab.png -------------------------------------------------------------------------------- /docs/thesis/images/debug.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/debug.log -------------------------------------------------------------------------------- /docs/thesis/images/discord-embedded-message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/discord-embedded-message.png -------------------------------------------------------------------------------- /docs/thesis/images/discord_client_struct.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/discord_client_struct.drawio.png -------------------------------------------------------------------------------- /docs/thesis/images/discord_direct_message_channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/discord_direct_message_channel.png -------------------------------------------------------------------------------- /docs/thesis/images/discord_text_channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/discord_text_channel.png -------------------------------------------------------------------------------- /docs/thesis/images/discord_voice_channel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/discord_voice_channel.png -------------------------------------------------------------------------------- /docs/thesis/images/doc-pdf-download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/doc-pdf-download.png -------------------------------------------------------------------------------- /docs/thesis/images/example_bunny_nft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/example_bunny_nft.png -------------------------------------------------------------------------------- /docs/thesis/images/feuni_discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/feuni_discord.png -------------------------------------------------------------------------------- /docs/thesis/images/ssfe_discord.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/ssfe_discord.png -------------------------------------------------------------------------------- /docs/thesis/images/topgg_find_servers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/images/topgg_find_servers.png -------------------------------------------------------------------------------- /docs/thesis/pdfa-daf-thesis.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/docs/thesis/pdfa-daf-thesis.pdf -------------------------------------------------------------------------------- /docs/thesis/scripts/generate_lit.py: -------------------------------------------------------------------------------- 1 | """ 2 | Scripts for generating thesis literature. 3 | (As footnotes) 4 | """ 5 | from typing import List, Dict 6 | import os 7 | import json 8 | 9 | 10 | OUTPUT_FILE = "../thesis_lit.rst" 11 | SOURCES_FILE = "./sources.json" 12 | 13 | LANGUAGE = os.environ.get("LANGUAGE", "sl") 14 | 15 | # Setup 16 | ## All paths relative to script file location 17 | os.chdir(os.path.dirname(__file__)) 18 | 19 | 20 | if LANGUAGE == "en": 21 | OUTPUT_HEADER = \ 22 | """ 23 | =============== 24 | Literature 25 | =============== 26 | """ 27 | 28 | OUTPUT_FORMAT = \ 29 | """ 30 | .. _{id}: 31 | 32 | :[{ind}]: {author}, "{title}", Available: {source} [Last checked: {updated}] 33 | """ 34 | else: 35 | OUTPUT_HEADER = \ 36 | """ 37 | =============== 38 | Literatura 39 | =============== 40 | """ 41 | 42 | OUTPUT_FORMAT = \ 43 | """ 44 | .. _{id}: 45 | 46 | :[{ind}]: {author}, "{title}", Dostopno: {source} [Dostopano: {updated}] 47 | """ 48 | 49 | OUTPUT_FOOTER = "\n" 50 | 51 | 52 | # Main script 53 | source_data = None 54 | source_output = OUTPUT_HEADER 55 | 56 | with open(SOURCES_FILE, "r", encoding="utf-8") as reader: 57 | source_data: List[Dict[str, str]] = json.load(reader) 58 | 59 | for i, item in enumerate(source_data, 1): 60 | author = item["author"] 61 | title = item["title"].replace(":", r"\:") 62 | source = item["source"] 63 | updated = item["updated"] 64 | id_ = item["id"] 65 | 66 | source_output += OUTPUT_FORMAT.format( 67 | ind=i, 68 | author=author, 69 | title=title, 70 | source=source, 71 | updated=updated, 72 | id=id_ 73 | ) 74 | 75 | source_output += OUTPUT_FOOTER 76 | with open(OUTPUT_FILE, "w", encoding="utf-8") as writer: 77 | writer.write(source_output) 78 | -------------------------------------------------------------------------------- /docs/thesis/sl/acknowledgements.rst: -------------------------------------------------------------------------------- 1 | 2 | .. raw:: latex 3 | 4 | \newpage 5 | 6 | .. only:: not latex 7 | 8 | ============= 9 | Zahvala 10 | ============= 11 | 12 | .. Prevent inclusion of this "title" into index 13 | .. raw:: latex 14 | 15 | \chapter*{Zahvala} 16 | 17 | Rad bi se zahvalil mentorju za nudenje podpore in pomoč pri izdelavi diplomskega dela. Prav tako bi se rad zahvalil 18 | vsem ostalim profesorjem, ki so nas poučevali in nudili strokovno podporo v zadnjih treh letih. 19 | Nazadnje bi se rad zahvalil staršema, ki sta me ves čas podpirala. 20 | 21 | .. raw:: latex 22 | 23 | \newpage 24 | -------------------------------------------------------------------------------- /docs/thesis/sl/appendix.rst: -------------------------------------------------------------------------------- 1 | 2 | ================== 3 | Priloge 4 | ================== 5 | 6 | 7 | Dodatne slike 8 | =============== 9 | 10 | .. raw:: latex 11 | 12 | \newpage 13 | 14 | 15 | .. _daf-gui-analytics-tab-rotated: 16 | .. figure:: ./DEP/daf-gui-analytics-tab-rotated.png 17 | :height: 20.5cm 18 | 19 | Zavihek *Analytics* 20 | 21 | 22 | .. _fig-gui-front: 23 | .. figure:: ./DEP/daf-gui-front-rotated.png 24 | :height: 20.5cm 25 | 26 | Grafični vmesnik (*Schema definition* zavihek) 27 | 28 | 29 | Primeri konfiguracije ogrodja 30 | ============================== 31 | 32 | .. |PY_EXAMPLE| replace:: jedro ogrodja 33 | .. |SCHEMA_EXAMPLE| replace:: GUI shema 34 | 35 | 36 | Pošiljanje sporočila z naključno periodo 37 | -------------------------------------------- 38 | Pošiljanje tekstovnega sporočila s periodo naključno med 1 uro in 2 urama, z začetkom pošiljanja 39 | 13.07.2023 00:00:00, kjer se sporočilo pošlje petkrat. 40 | 41 | .. _example-text-message-randomized-period: 42 | .. literalinclude:: ./DEP/Examples/example-text-message-randomized-period.py 43 | :caption: Pošiljanje sporočila z naključno periodo - |PY_EXAMPLE| 44 | 45 | .. literalinclude:: ./DEP/Examples/example-text-message-randomized-period.json 46 | :caption: Pošiljanje sporočila z naključno periodo - |SCHEMA_EXAMPLE| 47 | 48 | 49 | 50 | Avtomatsko odkrivanje (angl. *discovery*) cehov in kanalov 51 | ----------------------------------------------------------- 52 | Pošiljanje s fiksno periodo dveh ur in avtomatično odkrivanje pridruženih cehov in kanalov na podlagi RegEx vzorca. 53 | 54 | .. literalinclude:: ./DEP/Examples/example-autoguild-autochannel.py 55 | :caption: Avtomatsko odkrivanje cehov in kanalov - |PY_EXAMPLE| 56 | 57 | .. literalinclude:: ./DEP/Examples/example-autoguild-autochannel.json 58 | :caption: Avtomatsko odkrivanje cehov in kanalov - |SCHEMA_EXAMPLE| 59 | 60 | 61 | Oddaljen dostop 62 | ---------------------------------------- 63 | HTTP strežnik in GUI shema za povezovanje na ta strežnik. 64 | 65 | 66 | .. literalinclude:: ./DEP/Examples/example-remote.py 67 | :caption: Oddaljen dostop - |PY_EXAMPLE| 68 | 69 | .. literalinclude:: ./DEP/Examples/example-remote.json 70 | :caption: Oddaljen dostop - |SCHEMA_EXAMPLE| 71 | -------------------------------------------------------------------------------- /docs/thesis/sl/daf/dep_local.json: -------------------------------------------------------------------------------- 1 | { 2 | "copy": [ 3 | {"from": "../../../images/logo.png", "to": "./DEP/"}, 4 | {"from": "../../images/*.pdf", "to": "./DEP/"} 5 | ], 6 | "scripts": [] 7 | } -------------------------------------------------------------------------------- /docs/thesis/sl/daf/design_development/dep_local.json: -------------------------------------------------------------------------------- 1 | { 2 | "copy": [ 3 | {"from": "../../../../images/*", "to": "./DEP/"}, 4 | {"from": "../../../../source/dep_local.json", "to": "./DEP/_dep_local.json"}, 5 | {"from": "../../../../source/guide/GUI/images/gui-*", "to": "./DEP/images"}, 6 | {"from": "../../../images/*", "to": "./DEP/"}, 7 | {"from": "../../../../../testing/test_period_dynamic.py", "to": "./DEP/test_period_dynamic.py"} 8 | ], 9 | "scripts": [] 10 | } -------------------------------------------------------------------------------- /docs/thesis/sl/daf/design_development/index.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | Zasnova in razvoj 3 | ========================== 4 | 5 | 6 | 7 | .. toctree:: 8 | 9 | core 10 | gui 11 | docs 12 | testing 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/thesis/sl/daf/index.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | Ogrodje za oglaševanje po Discordu 3 | =================================== 4 | 5 | 6 | .. figure:: ./DEP/logo.png 7 | :height: 4cm 8 | 9 | Logotip projekta (Narejen z DALL-E & Adobe Photoshop) 10 | 11 | 12 | .. toctree:: 13 | 14 | purpose 15 | design_development/index 16 | -------------------------------------------------------------------------------- /docs/thesis/sl/daf/purpose.rst: -------------------------------------------------------------------------------- 1 | Namen projekta 2 | ================= 3 | Cilj projekta je izdelati ogrodje, ki lahko deluje 24 ur na dan in samodejno oglašuje vnaprej definirano ali dinamično vsebino, omogoča pregled poslanih sporočil in poročanje o uspešnosti preko beleženja zgodovine 4 | poslanih sporočil. 5 | Ker naj bi ogrodje delovalo brez prekinitev, je cilj izdelati ga na način, da bo delovalo kot demonski proces v ozadju, 6 | brez grafičnega vmesnika. 7 | 8 | Konfiguracijo ogrodja se bo izvedlo preko Python datoteke oz. skripte, katero se bo neposredno pognalo 9 | v Python okolju. Ker ta način konfiguracije zahteva nekaj dela in ni najbolj enostaven, je cilj izdelati 10 | tudi grafični vmesnik, ki bo deloval kot dodaten nivo nad samim jedrom ogrodja ter omogočal konfiguracijo in izvoz le-te 11 | na način, da se jo bo lahko uporabilo brez grafičnega vmesnika. 12 | 13 | Za lažji pregled dogajanja na strežniku je cilj na grafičnem vmesniku implementirati možnost oddaljenega dostopa, 14 | ki bo omogočal direktno manipulacijo s sporočili in pregled zgodovine poslanih sporočil za določitev uspešnosti oglaševanja. 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/thesis/sl/dep_local.json: -------------------------------------------------------------------------------- 1 | { 2 | "copy": [ 3 | {"from": "../../images/*", "to": "./DEP/"}, 4 | {"from": "../../source/guide/GUI/images/gui-*", "to": "./DEP/images"}, 5 | {"from": "../scripts/*", "to": "./DEP/"}, 6 | {"from": "../sources.json", "to": "./DEP/"}, 7 | {"from": "../images/*", "to": "./DEP/"}, 8 | {"from": "../ExampleUsage/*", "to": "./DEP/Examples/"} 9 | ], 10 | "scripts": ["./DEP/generate_lit.py"] 11 | } -------------------------------------------------------------------------------- /docs/thesis/sl/index.rst: -------------------------------------------------------------------------------- 1 | .. only:: not latex 2 | 3 | ================================ 4 | Front page of the thesis 5 | ================================ 6 | 7 | 8 | .. toctree:: 9 | 10 | glossary 11 | acknowledgements 12 | abstract 13 | introduction 14 | discord 15 | daf/index 16 | conclusion 17 | thesis_lit 18 | appendix 19 | 20 | -------------------------------------------------------------------------------- /docs/thesis/sl/introduction.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Uvod 3 | ==================== 4 | 5 | 6 | .. raw:: latex 7 | 8 | \pagenumbering{arabic} 9 | 10 | 11 | Nezamenljivi žetoni 12 | =========================== 13 | Nezamenljivi žetoni (angl. *Non fungible tokens*) so edinstvena digitalna sredstva, ki živijo na 14 | verigi blokov brez možnosti replikacije. 15 | Najpogosteje predstavljajo digitalna umetniška dela :ref:`nft_what_is`. 16 | 17 | 18 | .. figure:: ./DEP/example_bunny_nft.png 19 | :width: 5cm 20 | 21 | Primer nezameljivega žetona (ustvaril `DALL-E `_) 22 | 23 | 24 | Nezamenljivost pomeni, da posameznega žetona ni mogoče preprosto zamenjati za drugega, kot se lahko menja 25 | sod olja za drug sod olja ali en evro za drug evro. 26 | 27 | Najbližji primer nezamenljivega žetona v fizični obliki je bejzbolska kartica. Na primer, lahko imate zelo redko 28 | bejzbolsko kartico nekega igralca bejzbola in je ne morete enakovredno zamenjati za kakšno drugo, običajno bejzbolsko kartico. 29 | 30 | Marketinški pristopi za promoviranje nezamenljivih žetonov 31 | =========================================================== 32 | Obstaja več načinov oglaševanja, ki se jih lahko uporabi tudi za oglaševanje nezamenljivih žetonov. Ti so na primer 33 | uporaba Google Ads platforme (oglaševanje po Google iskalniku, YouTube aplikaciji), uporaba forumov in drugi načini. 34 | Eden izmed teh drugih načinov je morda še najbolj uveljavljen na tem področju, in sicer ga imenujemo 35 | agresivno oglaševanje (angl. *shilling*) :ref:`nft_shilling`. 36 | 37 | Pri agresivnem oglaševanju ni postavljanja promocijskega gradiva na spletno stran ali stojnice v javnost, temveč 38 | gre za nenehno objavljanje informacij o izdelku na socialna omrežja, kot so Instagram, Telegram, Discord ipd., 39 | omenjanje izdelka in deljenje povezav do njega povsod, kjer je to mogoče. 40 | 41 | Te dni prodajalci nezamenljivih žetonov pogosto ne oglašujejo samostojno, temveč najamejo ljudi, ki to delo 42 | opravljajo namesto njih. Obstaja veliko ponudb za taka dela, ki so lahko zelo profitabilna, še posebej če imate 43 | orodje, ki lahko oglašuje namesto človeka, avtomatično, brez da bi bil ta prisoten. 44 | 45 | To diplomsko delo se ne osredotoča na same nezamenljive žetone, temveč na proces oglaševanja, in sicer na socialnem 46 | omrežju Discord. Delo se navezuje na projekt Ogrodje za oglaševanje po Discordu (angl. *Discord Advertisement Framework*), ki je 47 | ogrodje za oglaševanje, napisano v programskem jeziku `Python `_. 48 | 49 | .. raw:: latex 50 | 51 | \newpage 52 | -------------------------------------------------------------------------------- /docs/thesis/sl/titlepage.tex: -------------------------------------------------------------------------------- 1 | \begin{titlepage} 2 | \thispagestyle{empty} 3 | \begin{center} 4 | {\large 5 | UNIVERZA V LJUBLJANI\\ 6 | FAKULTETA ZA ELEKTROTEHNIKO\\ 7 | } 8 | 9 | \vspace{3cm} 10 | {\LARGE David Hožič}\\ 11 | 12 | \vspace{2cm} 13 | {\textbf{\LARGE OGRODJE ZA OGLAŠEVANJE NEZAMENLJIVIH ŽETONOV PO SOCIALNEM OMREŽJU DISCORD }} 14 | 15 | \vspace{2cm} 16 | {\Large Diplomsko delo}\\ 17 | 18 | \vspace{1cm} 19 | {\Large Univerzitetni študijski program prve stopnje Elektrotehnika}\\ 20 | 21 | \vspace{2cm} 22 | {\Large Mentor: doc. dr. Matevž Pustišek}\\ 23 | \vfill 24 | {\Large Ljubljana, 2023} 25 | \end{center} 26 | \ \thispagestyle{empty} 27 | 28 | \end{titlepage} 29 | 30 | 31 | -------------------------------------------------------------------------------- /docs/thesis/sources.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "nft_what_is", 4 | "author": "investopedia (RAKESH SHARMA)", 5 | "title": "Non-Fungible Token (NFT): What It Means and How It Works", 6 | "source": "https://www.investopedia.com/non-fungible-tokens-nft-5115211", 7 | "updated": "01. 2023" 8 | }, 9 | { 10 | "id" : "nft_shilling", 11 | "author": "NFTing", 12 | "title": "What is NFT Shilling", 13 | "source": "https://nfting.medium.com/what-is-nft-shilling-192bec98429c", 14 | "updated": "07. 2023" 15 | }, 16 | { 17 | "id": "discord_company", 18 | "author": "Discord", 19 | "title": "Discord Company", 20 | "source": "https://discord.com/company", 21 | "updated":"07. 2023" 22 | }, 23 | { 24 | "id": "discord_interface", 25 | "author": "Discord", 26 | "title" : "Discord Interface", 27 | "source": "https://support.discord.com/hc/en-us/categories/200404398", 28 | "updated": "01. 2023" 29 | }, 30 | { 31 | "id": "discord_guidelines", 32 | "author": "Discord", 33 | "title": "Discord community guidelines", 34 | "source": "https://discord.com/guidelines", 35 | "updated": "07. 2023" 36 | }, 37 | { 38 | "id": "gpt3_content_generation", 39 | "author" : "GPT-3 (Open-AI)", 40 | "title" : "Uporaba GPT za generiranje oglaševalske vsebine", 41 | "source" : "https://openai.com/blog/gpt-3-apps", 42 | "updated" : "07. 2023" 43 | }, 44 | { 45 | "id": "top_gg_site", 46 | "author": "Top.GG", 47 | "source": "https://top.gg/", 48 | "title": "Top.GG webpage", 49 | "updated": "07. 2023" 50 | }, 51 | { 52 | "id" : "tkinter_py_docs", 53 | "author": "Python Software Foundation", 54 | "source" : "https://docs.python.org/3/library/tkinter.html#module-tkinter", 55 | "title": "tkinter — Python interface to Tcl/Tk", 56 | "updated": "05. 2023" 57 | }, 58 | { 59 | "id": "rst_docutils", 60 | "author": "Docutils", 61 | "title": "Docutils: Documentation Utilities", 62 | "source": "https://docutils.sourceforge.io/", 63 | "updated": "01. 2023" 64 | }, 65 | { 66 | "id" : "pytest_desc", 67 | "author": "Shaheer Shahid Malik", 68 | "source" : "https://medium.com/codex/why-use-pytest-to-test-your-software-project-7758ac9970ba", 69 | "title": "Why Use Pytest to Test Your Software Project?", 70 | "updated": "01. 2023" 71 | } 72 | ] 73 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools", 4 | "setuptools-scm", 5 | "wheel", 6 | ] 7 | 8 | build-backend = "setuptools.build_meta" 9 | 10 | 11 | [project] 12 | name = "discord-advert-framework" 13 | authors = [ 14 | {name = "David Hozic"} 15 | ] 16 | description = "Framework for periodic advertisements on Discord" 17 | readme = "README.rst" 18 | requires-python = ">=3.9" 19 | keywords = ["Discord", "Advertising", "Framework", "NFT", "Shilling"] 20 | classifiers = [ 21 | "Programming Language :: Python :: 3", 22 | "License :: OSI Approved :: MIT License", 23 | "Operating System :: OS Independent", 24 | ] 25 | 26 | 27 | dynamic = ["dependencies", "optional-dependencies", "version"] 28 | 29 | [project.gui-scripts] 30 | daf-gui="daf_gui:main.run" 31 | 32 | [tool.setuptools] 33 | include-package-data = true 34 | 35 | [tool.setuptools.dynamic] 36 | dependencies = {file = "requirements/mandatory.txt"} 37 | version = {attr = "daf.VERSION"} 38 | 39 | [tool.setuptools.dynamic.optional-dependencies] 40 | docs = {file = "requirements/docs.txt"} 41 | voice = {file = "requirements/voice.txt"} 42 | sql = {file = "requirements/sql.txt"} 43 | testing = {file = "requirements/testing.txt"} 44 | web = {file = "requirements/web.txt"} 45 | [tool.setuptools.dynamic.optional-dependencies.all] 46 | file = [ 47 | "requirements/voice.txt", 48 | "requirements/sql.txt", 49 | "requirements/web.txt" 50 | ] 51 | 52 | [tool.setuptools.packages.find] 53 | where = [ 54 | "src" 55 | ] 56 | 57 | [tool.pytest.ini_options] 58 | markers = [ 59 | "group_remote", 60 | ] 61 | asyncio_mode = "auto" 62 | -------------------------------------------------------------------------------- /requirements/docs.txt: -------------------------------------------------------------------------------- 1 | sphinx==8.2.3 2 | sphinx-autobuild==2024.9.19 3 | sphinx-copybutton==0.5.2 4 | furo==2024.8.6 5 | enum-tools[sphinx]==0.12.0 6 | sphinx-design[furo]==0.6.1 7 | readthedocs-sphinx-search==0.3.2 8 | sphinxcontrib-svg2pdfconverter==1.3.0 -------------------------------------------------------------------------------- /requirements/mandatory.txt: -------------------------------------------------------------------------------- 1 | aiohttp>=3.9.0,<3.12.0 2 | aiohttp_socks>=0.8,<0.11 3 | typeguard>=2.13,<2.14 4 | typing_extensions>=4,<5; python_version < "3.11" 5 | tkinter-async-execute>=1.2,<1.5 6 | asyncio-event-hub>=1.0,<1.2 7 | tkclasswiz>=1.4,<1.5 8 | ttkbootstrap==1.10.1 9 | audioop-lts~=0.2.1; python_version>='3.13' 10 | pillow>=10.4.0,<11.2.0 11 | -------------------------------------------------------------------------------- /requirements/sql.txt: -------------------------------------------------------------------------------- 1 | sqlalchemy[asyncio]>=2.0,<3.0 2 | aiosqlite>=0.19,<0.22 3 | pymssql>=2.2,<2.4 4 | asyncpg>=0.29,<0.31 5 | asyncmy>=0.2,<0.3 6 | -------------------------------------------------------------------------------- /requirements/testing.txt: -------------------------------------------------------------------------------- 1 | pytest>=7.4,<8.4 2 | pytest-asyncio>=0.21,<0.22 -------------------------------------------------------------------------------- /requirements/voice.txt: -------------------------------------------------------------------------------- 1 | PyNaCl>=1.5,<1.6 2 | -------------------------------------------------------------------------------- /requirements/web.txt: -------------------------------------------------------------------------------- 1 | selenium>=4.16,<4.30 2 | undetected-chromedriver>=3.5,<3.6 3 | webdriver-manager>=4.0,<4.1 4 | setuptools>=77.0,<77.1; python_version>='3.12' 5 | -------------------------------------------------------------------------------- /setup_build_env_do_not_run/install.ps1: -------------------------------------------------------------------------------- 1 | # Installs required build packages 2 | echo "Creating Python environment" 3 | python3 -m pip install virtualenv 4 | python3 -m virtualenv .venv 5 | .\.venv\Scripts\activate 6 | cp .\.venv\Scripts\python.exe .\.venv\Scripts\python3.exe 7 | cp .\.venv\Scripts\pythonw.exe .\.venv\Scripts\python3w.exe 8 | python3 -m pip install --editable .[all] 9 | python3 -m pip install --editable .[docs] 10 | python3 -m pip install --editable .[testing] 11 | 12 | # Intall scoop package manager and packages 13 | echo "Installing packages" 14 | Set-ExecutionPolicy RemoteSigned -Scope CurrentUser 15 | irm get.scoop.sh | iex 16 | scoop bucket add extras 17 | scoop install ffmpeg-shared inkscape 18 | 19 | # Install TexLive inside WSL 20 | wsl sudo apt install -y texlive-latex-base texlive-latex-extra texlive-lang-european latexmk build-essential 21 | -------------------------------------------------------------------------------- /setup_build_env_do_not_run/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | python3 -m pip install virtualenv 4 | python3 -m virtualenv .venv 5 | . ./.venv/bin/activate 6 | python3 -m pip install --editable .[all] 7 | python3 -m pip install --editable .[docs] 8 | python3 -m pip install --editable .[testing] 9 | 10 | sudo apt-get update 11 | sudo apt-get install -y texlive-latex-base texlive-latex-extra texlive-lang-european latexmk inkscape ffmpeg build-essential 12 | -------------------------------------------------------------------------------- /src/_discord/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Discord API Wrapper 3 | ~~~~~~~~~~~~~~~~~~~ 4 | 5 | A basic wrapper for the Discord API. 6 | 7 | :copyright: (c) 2015-2021 Rapptz & (c) 2021-present Pycord Development 8 | :license: MIT, see LICENSE for more details. 9 | """ 10 | 11 | __title__ = "pycord" 12 | __author__ = "Pycord Development" 13 | __license__ = "MIT" 14 | __copyright__ = "Copyright 2015-2021 Rapptz & Copyright 2021-present Pycord Development" 15 | 16 | __path__ = __import__("pkgutil").extend_path(__path__, __name__) 17 | 18 | import logging 19 | 20 | # We need __version__ to be imported first 21 | # isort: off 22 | from ._version import * 23 | 24 | # isort: on 25 | 26 | 27 | from . import abc, opus, sinks, ui, utils 28 | from .activity import * 29 | from .appinfo import * 30 | from .application_role_connection import * 31 | from .asset import * 32 | from .audit_logs import * 33 | from .automod import * 34 | from .bot import * 35 | from .channel import * 36 | from .client import * 37 | from .cog import * 38 | from .colour import * 39 | from .commands import * 40 | from .components import * 41 | from .embeds import * 42 | from .emoji import * 43 | from .enums import * 44 | from .errors import * 45 | from .file import * 46 | from .flags import * 47 | from .guild import * 48 | from .http import * 49 | from .integrations import * 50 | from .interactions import * 51 | from .invite import * 52 | from .member import * 53 | from .mentions import * 54 | from .message import * 55 | from .object import * 56 | from .partial_emoji import * 57 | from .permissions import * 58 | from .player import * 59 | from .raw_models import * 60 | from .reaction import * 61 | from .role import * 62 | from .scheduled_events import * 63 | from .shard import * 64 | from .stage_instance import * 65 | from .sticker import * 66 | from .team import * 67 | from .template import * 68 | from .threads import * 69 | from .user import * 70 | from .voice_client import * 71 | from .webhook import * 72 | from .welcome_screen import * 73 | from .widget import * 74 | 75 | logging.getLogger(__name__).addHandler(logging.NullHandler()) 76 | -------------------------------------------------------------------------------- /src/_discord/_typed_dict.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021-present Pycord Development 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | """ 24 | import sys 25 | 26 | # PEP 655 Required and NotRequired were added in python 3.11. This file is simply a 27 | # shortcut import, so we don't have to repeat this import logic across files. 28 | if sys.version_info >= (3, 11): 29 | from typing import NotRequired, Required, TypedDict 30 | else: 31 | from typing_extensions import NotRequired, Required, TypedDict 32 | 33 | __all__ = ( 34 | "Required", 35 | "NotRequired", 36 | "TypedDict", 37 | ) 38 | -------------------------------------------------------------------------------- /src/_discord/bin/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 1994-2013 Xiph.Org Foundation and contributors 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | - Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | - Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | - Neither the name of the Xiph.Org Foundation nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 22 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /src/_discord/bin/libopus-0.x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/src/_discord/bin/libopus-0.x64.dll -------------------------------------------------------------------------------- /src/_discord/bin/libopus-0.x86.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/src/_discord/bin/libopus-0.x86.dll -------------------------------------------------------------------------------- /src/_discord/commands/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from .context import * 27 | from .core import * 28 | from .options import * 29 | from .permissions import * 30 | -------------------------------------------------------------------------------- /src/_discord/ext/bridge/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from .bot import * 27 | from .context import * 28 | from .core import * 29 | -------------------------------------------------------------------------------- /src/_discord/ext/commands/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | discord.ext.commands 3 | ~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | An extension module to facilitate creation of bot commands. 6 | 7 | :copyright: (c) 2015-2021 Rapptz & (c) 2021-present Pycord Development 8 | :license: MIT, see LICENSE for more details. 9 | """ 10 | 11 | from .bot import * 12 | from .cog import * 13 | from .context import * 14 | from .converter import * 15 | from .cooldowns import * 16 | from .core import * 17 | from .errors import * 18 | from .flags import * 19 | from .help import * 20 | -------------------------------------------------------------------------------- /src/_discord/ext/commands/_types.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | 27 | from typing import TYPE_CHECKING, Any, Callable, Coroutine, TypeVar, Union 28 | 29 | if TYPE_CHECKING: 30 | from .cog import Cog 31 | from .context import Context 32 | from .errors import CommandError 33 | 34 | T = TypeVar("T") 35 | 36 | Coro = Coroutine[Any, Any, T] 37 | MaybeCoro = Union[T, Coro[T]] 38 | CoroFunc = Callable[..., Coro[Any]] 39 | 40 | Check = Union[ 41 | Callable[["Cog", "Context[Any]"], MaybeCoro[bool]], 42 | Callable[["Context[Any]"], MaybeCoro[bool]], 43 | ] 44 | Hook = Union[ 45 | Callable[["Cog", "Context[Any]"], Coro[Any]], Callable[["Context[Any]"], Coro[Any]] 46 | ] 47 | Error = Union[ 48 | Callable[["Cog", "Context[Any]", "CommandError"], Coro[Any]], 49 | Callable[["Context[Any]", "CommandError"], Coro[Any]], 50 | ] 51 | -------------------------------------------------------------------------------- /src/_discord/ext/pages/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | discord.ext.pages 3 | ~~~~~~~~~~~~~~~~~~~~~ 4 | An extension module to provide useful menu options. 5 | 6 | :copyright: 2021-present Pycord-Development 7 | :license: MIT, see LICENSE for more details. 8 | """ 9 | 10 | from .pagination import * 11 | -------------------------------------------------------------------------------- /src/_discord/mixins.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | __all__ = ( 27 | "EqualityComparable", 28 | "Hashable", 29 | ) 30 | 31 | 32 | class EqualityComparable: 33 | __slots__ = () 34 | 35 | id: int 36 | 37 | def __eq__(self, other: object) -> bool: 38 | return isinstance(other, self.__class__) and other.id == self.id 39 | 40 | def __ne__(self, other: object) -> bool: 41 | return not self.__eq__(other) 42 | 43 | 44 | class Hashable(EqualityComparable): 45 | __slots__ = () 46 | 47 | def __hash__(self) -> int: 48 | return self.id >> 22 49 | -------------------------------------------------------------------------------- /src/_discord/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/src/_discord/py.typed -------------------------------------------------------------------------------- /src/_discord/sinks/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | discord.sinks 3 | ~~~~~~~~~~~~~ 4 | 5 | A place to store all officially given voice sinks. 6 | 7 | :copyright: 2021-present Pycord Development 8 | :license: MIT, see LICENSE for more details. 9 | """ 10 | from .core import * 11 | from .errors import * 12 | from .m4a import * 13 | from .mka import * 14 | from .mkv import * 15 | from .mp3 import * 16 | from .mp4 import * 17 | from .ogg import * 18 | from .pcm import * 19 | from .wave import * 20 | -------------------------------------------------------------------------------- /src/_discord/sinks/pcm.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021-present Pycord Development 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | """ 24 | from .core import Filters, Sink, default_filters 25 | 26 | 27 | class PCMSink(Sink): 28 | """A special sink for .pcm files. 29 | 30 | .. versionadded:: 2.0 31 | """ 32 | 33 | def __init__(self, *, filters=None): 34 | if filters is None: 35 | filters = default_filters 36 | self.filters = filters 37 | Filters.__init__(self, **self.filters) 38 | 39 | self.encoding = "pcm" 40 | self.vc = None 41 | self.audio_data = {} 42 | 43 | def format_audio(self, audio): 44 | return 45 | -------------------------------------------------------------------------------- /src/_discord/sinks/wave.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021-present Pycord Development 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | """ 24 | import wave 25 | 26 | from .core import Filters, Sink, default_filters 27 | from .errors import WaveSinkError 28 | 29 | 30 | class WaveSink(Sink): 31 | """A special sink for .wav(wave) files. 32 | 33 | .. versionadded:: 2.0 34 | """ 35 | 36 | def __init__(self, *, filters=None): 37 | if filters is None: 38 | filters = default_filters 39 | self.filters = filters 40 | Filters.__init__(self, **self.filters) 41 | 42 | self.encoding = "wav" 43 | self.vc = None 44 | self.audio_data = {} 45 | 46 | def format_audio(self, audio): 47 | """Formats the recorded audio. 48 | 49 | Raises 50 | ------ 51 | WaveSinkError 52 | Audio may only be formatted after recording is finished. 53 | WaveSinkError 54 | Formatting the audio failed. 55 | """ 56 | if self.vc.recording: 57 | raise WaveSinkError( 58 | "Audio may only be formatted after recording is finished." 59 | ) 60 | data = audio.file 61 | 62 | with wave.open(data, "wb") as f: 63 | f.setnchannels(self.vc.decoder.CHANNELS) 64 | f.setsampwidth(self.vc.decoder.SAMPLE_SIZE // self.vc.decoder.CHANNELS) 65 | f.setframerate(self.vc.decoder.SAMPLING_RATE) 66 | 67 | data.seek(0) 68 | audio.on_format(self.encoding) 69 | -------------------------------------------------------------------------------- /src/_discord/types/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | discord.types 3 | ~~~~~~~~~~~~~~ 4 | 5 | Typings for the Discord API 6 | 7 | :copyright: (c) 2015-2021 Rapptz & (c) 2021-present Pycord Development 8 | :license: MIT, see LICENSE for more details. 9 | """ 10 | -------------------------------------------------------------------------------- /src/_discord/types/appinfo.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from __future__ import annotations 27 | 28 | from .._typed_dict import NotRequired, TypedDict 29 | from .snowflake import Snowflake 30 | from .team import Team 31 | from .user import User 32 | 33 | 34 | class BaseAppInfo(TypedDict): 35 | id: Snowflake 36 | name: str 37 | verify_key: str 38 | icon: str | None 39 | summary: str 40 | description: str 41 | terms_of_service_url: NotRequired[str] 42 | privacy_policy_url: NotRequired[str] 43 | hook: NotRequired[bool] 44 | max_participants: NotRequired[int] 45 | 46 | 47 | class AppInfo(BaseAppInfo): 48 | team: NotRequired[Team] 49 | guild_id: NotRequired[Snowflake] 50 | primary_sku_id: NotRequired[Snowflake] 51 | slug: NotRequired[str] 52 | rpc_origins: list[str] 53 | owner: User 54 | bot_public: bool 55 | bot_require_code_grant: bool 56 | 57 | 58 | class PartialAppInfo(BaseAppInfo): 59 | rpc_origins: NotRequired[list[str]] 60 | cover_image: NotRequired[str] 61 | flags: NotRequired[int] 62 | -------------------------------------------------------------------------------- /src/_discord/types/application_role_connection.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021-present Pycord Development 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | """ 24 | 25 | from __future__ import annotations 26 | 27 | from typing import Literal 28 | 29 | from .._typed_dict import NotRequired, TypedDict 30 | 31 | ApplicationRoleConnectionMetadataType = Literal[1, 2, 3, 4, 5, 6, 7, 8] 32 | 33 | 34 | class ApplicationRoleConnectionMetadata(TypedDict): 35 | type: ApplicationRoleConnectionMetadataType 36 | key: str 37 | name: str 38 | name_localizations: NotRequired[dict[str, str]] 39 | description: str 40 | description_localizations: NotRequired[dict[str, str]] 41 | -------------------------------------------------------------------------------- /src/_discord/types/emoji.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | from __future__ import annotations 26 | 27 | from typing import TypedDict 28 | 29 | from .snowflake import Snowflake, SnowflakeList 30 | from .user import User 31 | 32 | 33 | class PartialEmoji(TypedDict): 34 | id: Snowflake | None 35 | name: str | None 36 | 37 | 38 | class Emoji(PartialEmoji, total=False): 39 | roles: SnowflakeList 40 | user: User 41 | require_colons: bool 42 | managed: bool 43 | animated: bool 44 | available: bool 45 | 46 | 47 | class EditEmoji(TypedDict): 48 | name: str 49 | roles: SnowflakeList | None 50 | -------------------------------------------------------------------------------- /src/_discord/types/gateway.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from typing import TypedDict 27 | 28 | 29 | class SessionStartLimit(TypedDict): 30 | total: int 31 | remaining: int 32 | reset_after: int 33 | max_concurrency: int 34 | 35 | 36 | class Gateway(TypedDict): 37 | url: str 38 | 39 | 40 | class GatewayBot(Gateway): 41 | shards: int 42 | session_start_limit: SessionStartLimit 43 | -------------------------------------------------------------------------------- /src/_discord/types/integration.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from __future__ import annotations 27 | 28 | from typing import Literal, Union 29 | 30 | from .._typed_dict import NotRequired, TypedDict 31 | from .snowflake import Snowflake 32 | from .user import User 33 | 34 | 35 | class IntegrationApplication(TypedDict): 36 | bot: NotRequired[User] 37 | id: Snowflake 38 | name: str 39 | icon: str | None 40 | description: str 41 | summary: str 42 | 43 | 44 | class IntegrationAccount(TypedDict): 45 | id: str 46 | name: str 47 | 48 | 49 | IntegrationExpireBehavior = Literal[0, 1] 50 | 51 | 52 | class PartialIntegration(TypedDict): 53 | id: Snowflake 54 | name: str 55 | type: IntegrationType 56 | account: IntegrationAccount 57 | 58 | 59 | IntegrationType = Literal["twitch", "youtube", "discord"] 60 | 61 | 62 | class BaseIntegration(PartialIntegration): 63 | enabled: bool 64 | syncing: bool 65 | synced_at: str 66 | user: User 67 | expire_behavior: IntegrationExpireBehavior 68 | expire_grace_period: int 69 | 70 | 71 | class StreamIntegration(BaseIntegration): 72 | role_id: Snowflake | None 73 | enable_emoticons: bool 74 | subscriber_count: int 75 | revoked: bool 76 | 77 | 78 | class BotIntegration(BaseIntegration): 79 | application: IntegrationApplication 80 | 81 | 82 | Integration = Union[BaseIntegration, StreamIntegration, BotIntegration] 83 | -------------------------------------------------------------------------------- /src/_discord/types/member.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from typing import TypedDict 27 | 28 | from .snowflake import SnowflakeList 29 | from .user import User 30 | 31 | 32 | class Nickname(TypedDict): 33 | nick: str 34 | 35 | 36 | class PartialMember(TypedDict): 37 | roles: SnowflakeList 38 | joined_at: str 39 | deaf: bool 40 | mute: bool 41 | 42 | 43 | class Member(PartialMember, total=False): 44 | avatar: str 45 | user: User 46 | nick: str 47 | premium_since: str 48 | pending: bool 49 | permissions: str 50 | communication_disabled_until: str 51 | 52 | 53 | class _OptionalMemberWithUser(PartialMember, total=False): 54 | avatar: str 55 | nick: str 56 | premium_since: str 57 | pending: bool 58 | permissions: str 59 | 60 | 61 | class MemberWithUser(_OptionalMemberWithUser): 62 | user: User 63 | 64 | 65 | class UserWithMember(User, total=False): 66 | member: _OptionalMemberWithUser 67 | -------------------------------------------------------------------------------- /src/_discord/types/role.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from __future__ import annotations 27 | 28 | from .._typed_dict import NotRequired, TypedDict 29 | from .snowflake import Snowflake 30 | 31 | 32 | class Role(TypedDict): 33 | tags: NotRequired[RoleTags] 34 | id: Snowflake 35 | name: str 36 | color: int 37 | hoist: bool 38 | position: int 39 | permissions: str 40 | managed: bool 41 | mentionable: bool 42 | 43 | 44 | class RoleTags(TypedDict, total=False): 45 | bot_id: Snowflake 46 | integration_id: Snowflake 47 | premium_subscriber: None 48 | -------------------------------------------------------------------------------- /src/_discord/types/scheduled_events.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2021-present Pycord Development 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | """ 24 | 25 | from __future__ import annotations 26 | 27 | from typing import Literal, TypedDict 28 | 29 | from .member import Member 30 | from .snowflake import Snowflake 31 | from .user import User 32 | 33 | ScheduledEventStatus = Literal[1, 2, 3, 4] 34 | ScheduledEventLocationType = Literal[1, 2, 3] 35 | ScheduledEventPrivacyLevel = Literal[2] 36 | 37 | 38 | class ScheduledEvent(TypedDict): 39 | id: Snowflake 40 | guild_id: Snowflake 41 | channel_id: Snowflake 42 | creator_id: Snowflake 43 | name: str 44 | description: str 45 | image: str | None 46 | scheduled_start_time: str 47 | scheduled_end_time: str | None 48 | privacy_level: ScheduledEventPrivacyLevel 49 | status: ScheduledEventStatus 50 | entity_type: ScheduledEventLocationType 51 | entity_id: Snowflake 52 | entity_metadata: ScheduledEventEntityMetadata 53 | creator: User 54 | user_count: int | None 55 | 56 | 57 | class ScheduledEventEntityMetadata(TypedDict): 58 | location: str 59 | 60 | 61 | class ScheduledEventSubscriber(TypedDict): 62 | guild_scheduled_event_id: Snowflake 63 | user: User 64 | member: Member | None 65 | -------------------------------------------------------------------------------- /src/_discord/types/snowflake.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from typing import List, Union 27 | 28 | Snowflake = Union[str, int] 29 | SnowflakeList = List[Snowflake] 30 | -------------------------------------------------------------------------------- /src/_discord/types/team.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from __future__ import annotations 27 | 28 | from typing import TypedDict 29 | 30 | from .snowflake import Snowflake 31 | from .user import PartialUser 32 | 33 | 34 | class TeamMember(TypedDict): 35 | user: PartialUser 36 | membership_state: int 37 | permissions: list[str] 38 | team_id: Snowflake 39 | 40 | 41 | class Team(TypedDict): 42 | id: Snowflake 43 | name: str 44 | owner_id: Snowflake 45 | members: list[TeamMember] 46 | icon: str | None 47 | -------------------------------------------------------------------------------- /src/_discord/types/template.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from __future__ import annotations 27 | 28 | from typing import TypedDict 29 | 30 | from .guild import Guild 31 | from .snowflake import Snowflake 32 | from .user import User 33 | 34 | 35 | class CreateTemplate(TypedDict): 36 | name: str 37 | icon: bytes | None 38 | 39 | 40 | class Template(TypedDict): 41 | code: str 42 | name: str 43 | description: str | None 44 | usage_count: int 45 | creator_id: Snowflake 46 | creator: User 47 | created_at: str 48 | updated_at: str 49 | source_guild_id: Snowflake 50 | serialized_source_guild: Guild 51 | is_dirty: bool | None 52 | -------------------------------------------------------------------------------- /src/_discord/types/threads.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from __future__ import annotations 27 | 28 | from typing import Literal 29 | 30 | from .._typed_dict import NotRequired, TypedDict 31 | from ..flags import ChannelFlags 32 | from .snowflake import Snowflake 33 | 34 | ThreadType = Literal[10, 11, 12] 35 | ThreadArchiveDuration = Literal[60, 1440, 4320, 10080] 36 | 37 | 38 | class ThreadMember(TypedDict): 39 | id: Snowflake 40 | user_id: Snowflake 41 | join_timestamp: str 42 | flags: int 43 | 44 | 45 | class ThreadMetadata(TypedDict): 46 | invitable: NotRequired[bool] 47 | create_timestamp: NotRequired[str] 48 | archived: bool 49 | auto_archive_duration: ThreadArchiveDuration 50 | archive_timestamp: str 51 | locked: bool 52 | 53 | 54 | class Thread(TypedDict): 55 | member: NotRequired[ThreadMember] 56 | last_message_id: NotRequired[Snowflake | None] 57 | last_pin_timestamp: NotRequired[Snowflake | None] 58 | id: Snowflake 59 | guild_id: Snowflake 60 | parent_id: Snowflake 61 | owner_id: Snowflake 62 | name: str 63 | type: ThreadType 64 | member_count: int 65 | message_count: int 66 | rate_limit_per_user: int 67 | thread_metadata: ThreadMetadata 68 | flags: ChannelFlags 69 | total_message_sent: int 70 | 71 | 72 | class ThreadPaginationPayload(TypedDict): 73 | threads: list[Thread] 74 | members: list[ThreadMember] 75 | has_more: bool 76 | -------------------------------------------------------------------------------- /src/_discord/types/user.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | from __future__ import annotations 26 | 27 | from typing import Literal, TypedDict 28 | 29 | from .snowflake import Snowflake 30 | 31 | 32 | class PartialUser(TypedDict): 33 | id: Snowflake 34 | username: str 35 | discriminator: str 36 | global_name: str | None 37 | avatar: str | None 38 | 39 | 40 | PremiumType = Literal[0, 1, 2, 3] 41 | 42 | 43 | class User(PartialUser, total=False): 44 | bot: bool 45 | system: bool 46 | mfa_enabled: bool 47 | local: str 48 | verified: bool 49 | email: str | None 50 | flags: int 51 | premium_type: PremiumType 52 | public_flags: int 53 | -------------------------------------------------------------------------------- /src/_discord/types/webhook.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from __future__ import annotations 27 | 28 | from typing import Literal 29 | 30 | from .._typed_dict import NotRequired, TypedDict 31 | from .channel import PartialChannel 32 | from .snowflake import Snowflake 33 | from .user import User 34 | 35 | 36 | class SourceGuild(TypedDict): 37 | id: int 38 | name: str 39 | icon: str 40 | 41 | 42 | WebhookType = Literal[1, 2, 3] 43 | 44 | 45 | class FollowerWebhook(TypedDict): 46 | source_channel: NotRequired[PartialChannel] 47 | source_guild: NotRequired[SourceGuild] 48 | channel_id: Snowflake 49 | webhook_id: Snowflake 50 | 51 | 52 | class PartialWebhook(TypedDict): 53 | guild_id: NotRequired[Snowflake] 54 | user: NotRequired[User] 55 | token: NotRequired[str] 56 | id: Snowflake 57 | type: WebhookType 58 | 59 | 60 | class Webhook(PartialWebhook): 61 | name: NotRequired[str | None] 62 | avatar: NotRequired[str | None] 63 | channel_id: NotRequired[Snowflake] 64 | application_id: NotRequired[Snowflake | None] 65 | -------------------------------------------------------------------------------- /src/_discord/types/welcome_screen.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | 26 | from __future__ import annotations 27 | 28 | from typing import TypedDict 29 | 30 | from .snowflake import Snowflake 31 | 32 | 33 | class WelcomeScreen(TypedDict): 34 | description: str 35 | welcome_channels: list[WelcomeScreenChannel] 36 | 37 | 38 | class WelcomeScreenChannel(TypedDict): 39 | channel_id: Snowflake 40 | description: str 41 | emoji_id: Snowflake | None 42 | emoji_name: str | None 43 | -------------------------------------------------------------------------------- /src/_discord/types/widget.py: -------------------------------------------------------------------------------- 1 | """ 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2021 Rapptz 5 | Copyright (c) 2021-present Pycord Development 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a 8 | copy of this software and associated documentation files (the "Software"), 9 | to deal in the Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | and/or sell copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | """ 25 | from __future__ import annotations 26 | 27 | from .._typed_dict import NotRequired, TypedDict 28 | from .activity import Activity 29 | from .snowflake import Snowflake 30 | from .user import User 31 | 32 | 33 | class WidgetChannel(TypedDict): 34 | id: Snowflake 35 | name: str 36 | position: int 37 | 38 | 39 | class WidgetMember(User, total=False): 40 | nick: str 41 | game: Activity 42 | status: str 43 | avatar_url: str 44 | deaf: bool 45 | self_deaf: bool 46 | mute: bool 47 | self_mute: bool 48 | suppress: bool 49 | 50 | 51 | class Widget(TypedDict): 52 | channels: NotRequired[list[WidgetChannel]] 53 | members: NotRequired[list[WidgetMember]] 54 | presence_count: NotRequired[int] 55 | id: Snowflake 56 | name: str 57 | instant_invite: str 58 | 59 | 60 | class WidgetSettings(TypedDict): 61 | enabled: bool 62 | channel_id: Snowflake | None 63 | -------------------------------------------------------------------------------- /src/_discord/ui/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | discord.ui 3 | ~~~~~~~~~~ 4 | 5 | UI Kit helper for the Discord API 6 | 7 | :copyright: (c) 2015-2021 Rapptz & (c) 2021-present Pycord Development 8 | :license: MIT, see LICENSE for more details. 9 | """ 10 | 11 | from .button import * 12 | from .input_text import * 13 | from .item import * 14 | from .modal import * 15 | from .select import * 16 | from .view import * 17 | -------------------------------------------------------------------------------- /src/_discord/webhook/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | discord.webhook 3 | ~~~~~~~~~~~~~~~ 4 | 5 | Webhook support for the Discord API 6 | 7 | :copyright: (c) 2015-2021 Rapptz & (c) 2021-present Pycord Development 8 | :license: MIT, see LICENSE for more details. 9 | """ 10 | 11 | from .async_ import * 12 | from .sync import * 13 | -------------------------------------------------------------------------------- /src/daf/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Discord Advertisement Framework 3 | """ 4 | import _discord as discord 5 | 6 | from . import misc 7 | from . import events 8 | 9 | from .client import * 10 | from .core import * 11 | from .dtypes import * 12 | from .guild import * 13 | from .message import * 14 | from .logging import * 15 | from .web import * 16 | from .convert import * 17 | from .remote import * 18 | from .responder import * 19 | from .messagedata import * 20 | 21 | VERSION = "4.2.0" 22 | -------------------------------------------------------------------------------- /src/daf/dtypes.py: -------------------------------------------------------------------------------- 1 | """ 2 | The module contains definitions regarding the data types 3 | you can send using the xxxMESSAGE objects. 4 | """ 5 | from typing import Callable 6 | 7 | from .logging.tracing import * 8 | 9 | 10 | __all__ = ( 11 | "data_function", 12 | ) 13 | 14 | 15 | def data_function(fnc: Callable): 16 | """ 17 | Decorator used for wrapping a function that will return data to send when the message is ready. 18 | 19 | The ``fnc`` function must return data that is of type that the **x**\\ MESSAGE object supports. 20 | **If the type returned is not valid, the send attempt will simply be ignored and nothing will be logged at at**, 21 | this is useful if you want to use the ``fnc`` function to control whenever the message is ready to be sent. 22 | For example: if we have a function defined like this: 23 | 24 | .. code-block:: 25 | :emphasize-lines: 3 26 | 27 | @daf.data_function 28 | def get_data(): 29 | return None 30 | 31 | ... 32 | daf.TextMESSAGE(..., data=get_data()) 33 | ... 34 | 35 | then no messages will ever be sent, 36 | nor will any logs be made since invalid values are simply ignored by the framework. 37 | 38 | 39 | 40 | Parameters 41 | ------------ 42 | fnc: Callable 43 | The function to wrap. 44 | 45 | Returns 46 | ----------- 47 | FunctionCLASS 48 | A class for creating wrapper objects is returned. These wrapper objects can be used as 49 | a ``data`` parameter to the :ref:`Messages` objects. 50 | """ 51 | trace( 52 | "Using @data_function is deprecated and its usage is no longer allowed. Use DynamicMessageData / DynamicMessageData instead.", 53 | TraceLEVELS.ERROR, 54 | exception_cls=NameError 55 | ) 56 | -------------------------------------------------------------------------------- /src/daf/events.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module used to support listening and emitting events. 3 | It also contains the event loop definitions. 4 | """ 5 | from asyncio_event_hub import EventController 6 | from enum import Enum, auto 7 | 8 | 9 | 10 | __all__ = ( 11 | "EventID", 12 | "EventController", 13 | "get_global_event_ctrl", 14 | ) 15 | 16 | 17 | class GLOBAL: 18 | g_controller = EventController() 19 | 20 | 21 | def initialize(): 22 | """ 23 | Initializes the event module by creating the event loop task. 24 | Returns the event loop task, which's reference needs to be preserved. 25 | """ 26 | GLOBAL.g_controller.start() 27 | 28 | 29 | def get_global_event_ctrl() -> EventController: 30 | "Returns the global event controller" 31 | return GLOBAL.g_controller 32 | 33 | 34 | class EventID(Enum): 35 | """ 36 | Enum of all available events. 37 | 38 | Global events (:func:`get_global_event_ctrl`) have a 39 | ``g_`` prefix on their name. Other events are controlled by account bound :class:`daf.events.EventController`. 40 | """ 41 | # Global events 42 | g_daf_startup = 0 43 | g_daf_shutdown = auto() 44 | g_trace = auto() 45 | g_account_expired = auto() 46 | 47 | # Events that trigger internal actions 48 | # (for safety reasons) 49 | _trigger_account_update = auto() 50 | 51 | _trigger_message_ready = auto() 52 | _trigger_message_remove = auto() 53 | _trigger_message_add = auto() 54 | _trigger_message_update = auto() 55 | 56 | _trigger_server_remove = auto() 57 | _trigger_server_add = auto() 58 | _trigger_server_update = auto() 59 | _trigger_auto_guild_start_join = auto() 60 | 61 | _trigger_auto_responder_add = auto() 62 | _trigger_auto_responder_remove = auto() 63 | 64 | # Finished action events 65 | message_removed = auto() 66 | 67 | # Discord related events 68 | discord_member_join = auto() 69 | discord_invite_delete = auto() 70 | discord_guild_join = auto() 71 | discord_guild_remove = auto() 72 | discord_message = auto() 73 | 74 | _dummy = auto() # For stopping the event loop 75 | 76 | # Events for use externally (not within daf) 77 | _ws_disconnect = auto() 78 | -------------------------------------------------------------------------------- /src/daf/guild/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Subpackage containing guild related code. 3 | """ 4 | from .guilduser import * 5 | from .autoguild import * 6 | -------------------------------------------------------------------------------- /src/daf/logging/__init__.py: -------------------------------------------------------------------------------- 1 | "Package used for logging" 2 | from .sql import * 3 | from .tracing import * 4 | from ._logging import * 5 | -------------------------------------------------------------------------------- /src/daf/logging/sql/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | SQL logging package. 3 | """ 4 | 5 | from .mgr import * 6 | if SQL_INSTALLED: 7 | from .tables import * 8 | -------------------------------------------------------------------------------- /src/daf/message/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | This sub-package contains the message definitions. 3 | It is a separate package to reduce number of lines per file.""" 4 | from .base import * 5 | from .text_based import * 6 | from .messageperiod import * 7 | from .autochannel import * 8 | from .constraints import * 9 | 10 | try: 11 | from .voice_based import * 12 | except ModuleNotFoundError: 13 | pass -------------------------------------------------------------------------------- /src/daf/message/constraints.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implements additional message constraints, that are required to pass 3 | for a message to be sent. 4 | 5 | .. versionadded:: 4.1 6 | """ 7 | from __future__ import annotations 8 | from abc import abstractmethod, ABC 9 | from _discord import TextChannel 10 | 11 | from .autochannel import AutoCHANNEL 12 | from ..misc import doc_category 13 | 14 | 15 | __all__ = ("AntiSpamMessageConstraint",) 16 | 17 | 18 | class BaseMessageConstraint(ABC): 19 | @abstractmethod 20 | def check(self, channels: list[TextChannel]) -> list[TextChannel]: 21 | """ 22 | Checks if the message can be sent based on the configured check. 23 | """ 24 | 25 | 26 | @doc_category("Message constraints") 27 | class AntiSpamMessageConstraint(BaseMessageConstraint): 28 | """ 29 | Prevents a new message to be sent if the last message in the same channel was 30 | sent by us, thus preventing spam on inactivate channels. 31 | 32 | .. versionadded:: 4.1 33 | """ 34 | def __init__(self, per_channel: bool = True) -> None: 35 | self.per_channel = per_channel 36 | super().__init__() 37 | 38 | def check(self, channels: list[TextChannel | AutoCHANNEL]) -> list[TextChannel]: 39 | allowed = list(filter( 40 | lambda channel: channel.last_message is None or 41 | channel.last_message.author.id != channel._state.user.id, channels 42 | )) 43 | if not self.per_channel and len(allowed) != len(channels): # In global mode, only allow to all channels 44 | return [] 45 | 46 | return allowed 47 | -------------------------------------------------------------------------------- /src/daf/messagedata/__init__.py: -------------------------------------------------------------------------------- 1 | from .basedata import * 2 | from .textdata import * 3 | from .voicedata import * 4 | from .dynamicdata import * 5 | 6 | from .file import * 7 | -------------------------------------------------------------------------------- /src/daf/messagedata/basedata.py: -------------------------------------------------------------------------------- 1 | from abc import abstractmethod, ABC 2 | from typing import TypedDict 3 | 4 | 5 | __all__ = ("BaseMessageData",) 6 | 7 | 8 | class BaseMessageData(ABC): 9 | """ 10 | Interface for message data. 11 | The interface enforces the definition of ``to_dict`` method, 12 | which must return a ``TypedDict``. 13 | """ 14 | 15 | @abstractmethod 16 | async def to_dict(self) -> TypedDict: 17 | pass 18 | 19 | -------------------------------------------------------------------------------- /src/daf/messagedata/textdata.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional, Optional 2 | from dataclasses import dataclass, asdict, field 3 | 4 | from .basedata import BaseMessageData 5 | from ..misc.doc import doc_category 6 | from .file import FILE 7 | 8 | import _discord as discord 9 | 10 | 11 | __all__ = ("BaseTextData", "TextMessageData",) 12 | 13 | 14 | class BaseTextData(BaseMessageData): 15 | """ 16 | Interface for text message data. 17 | """ 18 | 19 | 20 | @doc_category("Message data", path="messagedata") 21 | @dataclass 22 | class TextMessageData(BaseTextData): 23 | """ 24 | Represents fixed text message data. 25 | """ 26 | 27 | content: Optional[str] = None 28 | embed: Optional[discord.Embed] = None 29 | files: List[FILE] = field(default_factory=list) 30 | 31 | async def to_dict(self) -> dict: 32 | return asdict(self) 33 | -------------------------------------------------------------------------------- /src/daf/messagedata/voicedata.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass, asdict 2 | 3 | from .basedata import BaseMessageData 4 | from ..misc.doc import doc_category 5 | from .file import FILE 6 | 7 | 8 | __all__ = ("BaseVoiceData", "VoiceMessageData",) 9 | 10 | 11 | class BaseVoiceData(BaseMessageData): 12 | """ 13 | Interface for voice-like / audio-like data. 14 | """ 15 | 16 | 17 | @doc_category("Message data", path="messagedata") 18 | @dataclass 19 | class VoiceMessageData(BaseVoiceData): 20 | """ 21 | Represents fixed voice-like data. 22 | """ 23 | file: FILE 24 | 25 | async def to_dict(self) -> dict: 26 | return asdict(self) 27 | -------------------------------------------------------------------------------- /src/daf/misc/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utilities package. 3 | Contains miscellaneous utilities. 4 | """ 5 | 6 | from .async_util import * 7 | from .attributes import * 8 | from .cache import * 9 | from .doc import * 10 | from .instance_track import * 11 | -------------------------------------------------------------------------------- /src/daf/misc/attributes.py: -------------------------------------------------------------------------------- 1 | """ 2 | Attribute manipulation utitilities. 3 | """ 4 | from typing import Any 5 | from itertools import chain 6 | from contextlib import suppress 7 | from inspect import _empty 8 | 9 | 10 | __all__ = ( 11 | "write_non_exist", 12 | "get_all_slots", 13 | ) 14 | 15 | 16 | def write_non_exist(obj: Any, name: str, value: Any): 17 | """ 18 | Method that assigns an attribute only if it does not already exist. 19 | This is to prevent any ``.update()`` method calls from resetting critical 20 | variables that should not be changed, 21 | even if the objects goes thru initialization again. 22 | 23 | Parameters 24 | ------------- 25 | obj: Any 26 | Object to safely write. 27 | 28 | name: str 29 | The name of the attribute to change. 30 | 31 | value: Any 32 | The value to change the attribute with. 33 | """ 34 | # Write only if forced, or if not forced, then the attribute must not exist 35 | if getattr(obj, name, None) is None: 36 | setattr(obj, name, value) 37 | 38 | 39 | def get_all_slots(cls) -> list: 40 | """ 41 | Returns slots of current class and it's bases. Skips the __weakref__ slot. 42 | Also returns internal_daf_id descriptor for tracked objects 43 | """ 44 | ret = list(chain.from_iterable(getattr(class_, '__slots__', []) for class_ in cls.__mro__)) 45 | 46 | with suppress(ValueError): 47 | ret.remove("__weakref__") 48 | 49 | return ret 50 | -------------------------------------------------------------------------------- /src/daf/misc/cache.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utility module used for caching. 3 | """ 4 | from typing import Callable 5 | from functools import wraps 6 | import pickle 7 | 8 | 9 | __all__ = ( 10 | "cache_result", 11 | ) 12 | 13 | 14 | # Caching 15 | def cache_result(max: int = 256): 16 | """ 17 | Caching function that also allows dictionary and lists to be used as a key. 18 | 19 | Parameters 20 | -------------- 21 | max: int 22 | The maximum number of items inside the cache. 23 | """ 24 | def _decorator(fnc: Callable): 25 | cache_dict = {} 26 | 27 | @wraps(fnc) 28 | def wrapper(*args, **kwargs): 29 | try: 30 | # Convert to pickle string to allow hashing of non-hashables (dictionaries, lists, ...) 31 | key = pickle.dumps((*args, kwargs)) 32 | except Exception: 33 | return fnc(*args, **kwargs) 34 | 35 | result = cache_dict.get(key, Ellipsis) 36 | if result is not Ellipsis: 37 | return result 38 | 39 | result = fnc(*args, **kwargs) 40 | cache_dict[key] = result 41 | 42 | if len(cache_dict) > max: 43 | items = list(cache_dict.items())[:max // 2] 44 | cache_dict.clear() 45 | cache_dict.update(items) 46 | 47 | return result 48 | 49 | return wrapper 50 | 51 | return _decorator 52 | -------------------------------------------------------------------------------- /src/daf/misc/doc.py: -------------------------------------------------------------------------------- 1 | """ 2 | Utility module for documentation. 3 | """ 4 | # Documentation 5 | from typing import Optional, Dict, Literal 6 | from os import environ 7 | 8 | 9 | __all__ = ( 10 | "doc_category", 11 | ) 12 | 13 | DOCUMENTATION_MODE = bool(environ.get("DOCUMENTATION", False)) 14 | if DOCUMENTATION_MODE: 15 | cat_map: Dict[str, list] = {"Program": {}, "HTTP": {}} 16 | 17 | 18 | def doc_category( 19 | cat: str, 20 | manual: Optional[bool] = False, 21 | path: Optional[str] = None, 22 | api_type: Literal["Program", "HTTP"] = "Program" 23 | ): 24 | """ 25 | Used to mark the object for documentation. 26 | Objects marked with this decorator function will 27 | have :mod:`sphinx.ext.autodoc` directives generated automatically. 28 | 29 | Parameters 30 | ------------ 31 | cat: str 32 | The name of the category to put this in. 33 | manual: Optional[bool] 34 | Generate ``function`` directives instead of ``autofunction``. 35 | Should be used when dealing with overloads. 36 | path: Optional[str] 37 | Custom path to the object. 38 | api_type: Literal["Program", "HTTP"] 39 | The type of API, the documented item belongs to. 40 | Defaults to 'Program' 41 | """ 42 | def _category(item): # item == class or function 43 | if DOCUMENTATION_MODE: 44 | cat_map[api_type][cat].append((item, manual, path)) 45 | return item 46 | 47 | if DOCUMENTATION_MODE: 48 | if cat not in cat_map[api_type]: 49 | cat_map[api_type][cat] = [] 50 | 51 | return _category 52 | -------------------------------------------------------------------------------- /src/daf/responder/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module implements message-responding functionality. 3 | """ 4 | from .base import ResponderBase 5 | from .dmresponder import DMResponder 6 | from .guildresponder import GuildResponder 7 | 8 | from .constraints import * 9 | from .actions import * 10 | from ..logic import * 11 | -------------------------------------------------------------------------------- /src/daf/responder/actions/__init__.py: -------------------------------------------------------------------------------- 1 | from .response import * 2 | -------------------------------------------------------------------------------- /src/daf/responder/actions/response.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typeguard import typechecked 3 | 4 | from ...messagedata import BaseTextData 5 | from ...misc.doc import doc_category 6 | 7 | import _discord as discord 8 | 9 | 10 | __all__ = ("BaseResponse", "DMResponse", "GuildResponse") 11 | 12 | 13 | @doc_category("Auto responder") 14 | class BaseResponse(ABC): 15 | """ 16 | Base response class. 17 | 18 | Parameters 19 | ---------------- 20 | data: BaseTextData 21 | The data that can be sent into the text / DM channel. 22 | """ 23 | @typechecked 24 | def __init__(self, data: BaseTextData) -> None: 25 | self.data = data 26 | 27 | @abstractmethod 28 | async def perform(self, message: discord.Message): 29 | """ 30 | Perform the action. 31 | 32 | Parameters 33 | ----------- 34 | message: discord.Message 35 | """ 36 | pass 37 | 38 | 39 | @doc_category("Auto responder") 40 | class DMResponse(BaseResponse): 41 | """ 42 | DM response class. Used for responding into DM messages 43 | of the message's author. 44 | 45 | Parameters 46 | ---------------- 47 | data: BaseTextData 48 | The data that will be sent into message author's DM channel. 49 | """ 50 | async def perform(self, message: discord.Message): 51 | data = await self.data.to_dict() 52 | await message.author.send( 53 | content=data["content"], 54 | embed=data["embed"], 55 | files=[discord.File(x.stream, filename=x.filename) for x in data["files"]] 56 | ) 57 | 58 | 59 | @doc_category("Auto responder") 60 | class GuildResponse(BaseResponse): 61 | """ 62 | Guild response class. Used for responding into the same channel 63 | as the message that triggered the response. 64 | The response is a reply. 65 | 66 | Parameters 67 | ---------------- 68 | data: BaseTextData 69 | The data that will be sent into the channel. 70 | """ 71 | async def perform(self, message: discord.Message): 72 | data = await self.data.to_dict() 73 | await message.reply( 74 | content=data["content"], 75 | embed=data["embed"], 76 | files=[discord.File(x.stream, filename=x.filename) for x in data["files"]] 77 | ) 78 | -------------------------------------------------------------------------------- /src/daf/responder/base.py: -------------------------------------------------------------------------------- 1 | 2 | from abc import ABC, abstractmethod 3 | from typing import List 4 | 5 | from .constraints import ConstraintBase 6 | from .actions import BaseResponse 7 | from ..logic import BaseLogic 8 | from ..events import EventID 9 | 10 | import asyncio_event_hub as aeh 11 | import _discord as discord 12 | 13 | 14 | __all__ = ("ResponderBase",) 15 | 16 | 17 | class ResponderBase(ABC): 18 | """ 19 | The responder is an object capable of making automatic replies to messages based on some 20 | keyword condition and constraints. 21 | 22 | Parameters 23 | -------------- 24 | condition: BaseLogic 25 | The match condition. The condition represents the 26 | match condition of message's text. 27 | action: BaseResponse 28 | Represents the action taken on both ``condition`` and ``constraints`` being fulfilled. 29 | constraints: list[ConstraintBase] 30 | In addition to ``condition``, constraints add additional checks that need to be fulfilled 31 | before performing an action. 32 | All of the constraints inside the ``constraints`` list need to be fulfilled. 33 | """ 34 | __slots__ = ( 35 | "condition", 36 | "constraints", 37 | "action", 38 | "event_ctrl", 39 | "client", 40 | ) 41 | 42 | def __init__( 43 | self, 44 | condition: BaseLogic, 45 | action: BaseResponse, 46 | constraints: List[ConstraintBase] 47 | ) -> None: 48 | self.condition = condition 49 | self.constraints = constraints 50 | self.action = action 51 | self.event_ctrl: aeh.EventController = None 52 | self.client: discord.Client = None 53 | 54 | async def handle_message(self, message: discord.Message): 55 | "Processes message and performs an action if all constraints satisfied." 56 | for const in self.constraints: # Check constraints 57 | if not const.check(message, self.client): 58 | return 59 | 60 | # Check keywords 61 | if not self.condition.check(message.clean_content): 62 | return 63 | 64 | await self.action.perform(message) # All constraints satisfied 65 | 66 | @abstractmethod 67 | async def initialize(self, event_ctrl: aeh.EventController, client: discord.Client): 68 | pass 69 | 70 | def close(self): 71 | self.event_ctrl.remove_listener(EventID.discord_message, self.handle_message) 72 | -------------------------------------------------------------------------------- /src/daf/responder/constraints/__init__.py: -------------------------------------------------------------------------------- 1 | from .baseconstraint import ConstraintBase 2 | from .guildconstraint import * 3 | from .dmconstraint import * 4 | -------------------------------------------------------------------------------- /src/daf/responder/constraints/baseconstraint.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implements the base constraint. 3 | """ 4 | from abc import ABC, abstractmethod 5 | 6 | from ...misc.doc import doc_category 7 | 8 | import _discord as discord 9 | 10 | 11 | __all__ = ("ConstraintBase", ) 12 | 13 | @doc_category("Auto responder") 14 | class ConstraintBase(ABC): 15 | @abstractmethod 16 | def check(self, message: discord.Message, client: discord.Client) -> bool: 17 | """ 18 | Verifies if the constraint is fulfilled. 19 | 20 | Parameters 21 | ------------- 22 | message: :class:`discord.Message` 23 | Potential message to be responded to. 24 | """ 25 | pass 26 | -------------------------------------------------------------------------------- /src/daf/responder/constraints/dmconstraint.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | from typeguard import typechecked 3 | 4 | from .baseconstraint import ConstraintBase 5 | from ...misc.doc import doc_category 6 | 7 | import _discord as discord 8 | 9 | 10 | __all__ = ("BaseDMConstraint", "MemberOfGuildConstraint") 11 | 12 | 13 | @doc_category("Auto responder") 14 | class BaseDMConstraint(ConstraintBase): 15 | """ 16 | Base for constraints that are DM specific. 17 | """ 18 | 19 | @doc_category("Auto responder") 20 | class MemberOfGuildConstraint(BaseDMConstraint): 21 | """ 22 | Constraint that checks if the DM message author 23 | is part of the ``guild``. 24 | 25 | Parameters 26 | ---------------- 27 | guild: int | discord.Guild 28 | The guild to which the message's author must belong for the constraint to be fulfilled. 29 | """ 30 | @typechecked 31 | def __init__(self, guild: Union[int, discord.Guild]) -> None: 32 | self.guild = guild if isinstance(guild, int) else guild.id 33 | 34 | def check(self, message: discord.Message, client: discord.Client) -> bool: 35 | guild = client.get_guild(self.guild) 36 | return guild is not None and guild.get_member(message.author.id) is not None 37 | -------------------------------------------------------------------------------- /src/daf/responder/constraints/guildconstraint.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | from typeguard import typechecked 3 | 4 | from .baseconstraint import ConstraintBase 5 | from ...misc.doc import doc_category 6 | 7 | import _discord as discord 8 | 9 | 10 | __all__ = ("BaseGuildConstraint", "GuildConstraint") 11 | 12 | 13 | @doc_category("Auto responder") 14 | class BaseGuildConstraint(ConstraintBase): 15 | """ 16 | Constraint base for all guild constraints. 17 | """ 18 | 19 | @doc_category("Auto responder") 20 | class GuildConstraint(BaseGuildConstraint): 21 | """ 22 | Constraint that checks if the message originated 23 | from the specific ``guild``. 24 | 25 | Parameters 26 | ---------------- 27 | guild: int | discord.Guild 28 | The guild to which the message must be sent for the constraint to be fulfilled. 29 | """ 30 | @typechecked 31 | def __init__(self, guild: Union[int, discord.Guild]) -> None: 32 | self.guild = guild if isinstance(guild, int) else guild.id 33 | 34 | def check(self, message: discord.Message, client: discord.Client) -> bool: 35 | return message.guild and message.guild.id == self.guild 36 | -------------------------------------------------------------------------------- /src/daf/responder/dmresponder.py: -------------------------------------------------------------------------------- 1 | from typeguard import typechecked 2 | from typing import List 3 | 4 | from ..misc.instance_track import track_id 5 | from .constraints import BaseDMConstraint 6 | from ..misc.doc import doc_category 7 | from .actions import DMResponse 8 | from .base import ResponderBase 9 | from ..logic import BaseLogic 10 | from ..events import EventID 11 | 12 | import asyncio_event_hub as aeh 13 | import _discord as discord 14 | 15 | 16 | __all__ = ("DMResponder",) 17 | 18 | 19 | @track_id 20 | @doc_category("Auto responder", path="responder") 21 | class DMResponder(ResponderBase): 22 | __doc__ = "DM responder implementation. " + ResponderBase.__doc__ 23 | __slots__ = tuple() 24 | 25 | @typechecked 26 | def __init__( 27 | self, 28 | condition: BaseLogic, 29 | action: DMResponse, 30 | constraints: List[BaseDMConstraint] = [], 31 | ) -> None: 32 | super().__init__(condition, action, constraints) 33 | 34 | async def initialize(self, event_ctrl: aeh.EventController, client: discord.Client): 35 | event_ctrl.add_listener( 36 | EventID.discord_message, 37 | self.handle_message, 38 | lambda m: isinstance(m.channel, discord.DMChannel) 39 | ) 40 | self.event_ctrl = event_ctrl 41 | self.client = client 42 | -------------------------------------------------------------------------------- /src/daf/responder/guildresponder.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from typeguard import typechecked 3 | 4 | from .constraints import BaseGuildConstraint 5 | from ..misc.instance_track import track_id 6 | from ..misc.doc import doc_category 7 | from .actions import BaseResponse 8 | from .base import ResponderBase 9 | from ..logic import BaseLogic 10 | from ..events import EventID 11 | 12 | import asyncio_event_hub as aeh 13 | import _discord as discord 14 | 15 | 16 | __all__ = ("GuildResponder",) 17 | 18 | 19 | @track_id 20 | @doc_category("Auto responder", path="responder") 21 | class GuildResponder(ResponderBase): 22 | __doc__ = "Guild responder implementation. " + ResponderBase.__doc__ 23 | __slots__ = tuple() 24 | 25 | @typechecked 26 | def __init__( 27 | self, 28 | condition: BaseLogic, 29 | action: BaseResponse, 30 | constraints: List[BaseGuildConstraint] = [], 31 | ) -> None: 32 | super().__init__(condition, action, constraints) 33 | 34 | async def initialize(self, event_ctrl: aeh.EventController, client: discord.Client): 35 | event_ctrl.add_listener( 36 | EventID.discord_message, 37 | self.handle_message, 38 | lambda m: 39 | isinstance(m.channel, discord.TextChannel) and 40 | (member := m.guild.get_member(client.user.id)) and 41 | not member.pending and 42 | m.channel.permissions_for(member).send_messages 43 | ) 44 | self.event_ctrl = event_ctrl 45 | self.client = client 46 | -------------------------------------------------------------------------------- /src/daf_gui/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Graphical interface for Discord Advertisement Framework. 3 | """ 4 | from .main import run 5 | from .tod_extensions.loader import register_extensions, register_annotations, register_conversions, register_deprecations 6 | register_extensions() 7 | register_annotations() 8 | register_conversions() 9 | register_deprecations() 10 | -------------------------------------------------------------------------------- /src/daf_gui/__main__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Startup file, that can be used to start the framework with 'python -m daf_gui'. 3 | """ 4 | from . import main 5 | 6 | main.run() 7 | -------------------------------------------------------------------------------- /src/daf_gui/edit_window_manager.py: -------------------------------------------------------------------------------- 1 | from tkclasswiz import ObjectEditWindow 2 | 3 | import ttkbootstrap.dialogs as tkdiag 4 | 5 | 6 | __all__ = ( 7 | "EditWindowManager", 8 | ) 9 | 10 | 11 | class EditWindowManager: 12 | "Manager class for graphically editing objects" 13 | def __init__(self) -> None: 14 | self.window = None 15 | 16 | def open_object_edit_window(self, *args, **kwargs): 17 | if self.window is None or self.window.closed: 18 | self.window = ObjectEditWindow() 19 | self.window.open_object_edit_frame(*args, **kwargs) 20 | else: 21 | tkdiag.Messagebox.show_error("Object edit window is already open, close it first.", "Already open") 22 | self.window.focus() 23 | -------------------------------------------------------------------------------- /src/daf_gui/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/src/daf_gui/img/logo.png -------------------------------------------------------------------------------- /src/daf_gui/tabs/__init__.py: -------------------------------------------------------------------------------- 1 | from .analytics import * 2 | from .optional import * 3 | from .schema import * 4 | from .about import * 5 | from .debug import * 6 | from .live import * -------------------------------------------------------------------------------- /src/daf_gui/tabs/about.py: -------------------------------------------------------------------------------- 1 | import ttkbootstrap as ttk 2 | 3 | from tkclasswiz.dpi import dpi_scaled 4 | from PIL import Image, ImageTk 5 | 6 | import webbrowser 7 | import daf 8 | import os 9 | 10 | 11 | __all__ = ( 12 | "AboutTab", 13 | ) 14 | 15 | 16 | CREDITS_TEXT = \ 17 | """ 18 | Welcome to Discord Advertisement Framework - UI mode. 19 | The UI runs on top of Discord Advertisement Framework and allows easier usage for those who 20 | don't want to write Python code to use the software. 21 | 22 | This is written as part of my bachelor thesis as a degree finishing project 23 | "Framework for advertising NFT on social network Discord". 24 | """ 25 | 26 | GITHUB_URL = "https://github.com/davidhozic/discord-advertisement-framework" 27 | DOC_URL = f"https://daf.davidhozic.com/en/v{'.'.join(daf.VERSION.split('.')[:2])}.x/" 28 | DISCORD_URL = "https://discord.gg/DEnvahb2Sw" 29 | 30 | 31 | class AboutTab(ttk.Frame): 32 | def __init__(self, *args, **kwargs) -> None: 33 | super().__init__(*args, **kwargs) 34 | dpi_10 = dpi_scaled(10) 35 | dpi_30 = dpi_scaled(30) 36 | logo_img = Image.open(f"{os.path.dirname(__file__)}/../img/logo.png") 37 | logo_img = logo_img.resize( 38 | (dpi_scaled(400), dpi_scaled(400)), 39 | resample=0 40 | ) 41 | logo = ImageTk.PhotoImage(logo_img) 42 | info_bnts_frame = ttk.Frame(self) 43 | info_bnts_frame.pack(pady=dpi_30) 44 | ttk.Button(info_bnts_frame, text="Github", command=lambda: webbrowser.open(GITHUB_URL)).grid(row=0, column=0) 45 | ttk.Button( 46 | info_bnts_frame, 47 | text="Documentation", 48 | command=lambda: webbrowser.open(DOC_URL) 49 | ).grid(row=0, column=1) 50 | ttk.Button( 51 | info_bnts_frame, 52 | text="My Discord server", 53 | command=lambda: webbrowser.open(DISCORD_URL) 54 | ).grid(row=0, column=2) 55 | ttk.Label(self, text="Like the app? Give it a star :) on GitHub (^)").pack(pady=dpi_10) 56 | ttk.Label(self, text=CREDITS_TEXT).pack() 57 | label_logo = ttk.Label(self, image=logo) 58 | label_logo.image = logo 59 | label_logo.pack() 60 | -------------------------------------------------------------------------------- /src/daf_gui/tabs/debug.py: -------------------------------------------------------------------------------- 1 | import ttkbootstrap as ttk 2 | import tkinter as tk 3 | 4 | from tkclasswiz.storage import ListBoxScrolled 5 | 6 | import daf 7 | import sys 8 | 9 | 10 | __all__ = ( 11 | "DebugTab", 12 | ) 13 | 14 | 15 | class DebugTab(ttk.Frame): 16 | def __init__(self, *args, **kwargs) -> None: 17 | super().__init__(*args, **kwargs) 18 | text_output = ListBoxScrolled(self) 19 | text_output.unbind("") 20 | text_output.unbind("") 21 | text_output.unbind("") 22 | text_output.pack(fill=tk.BOTH, expand=True) 23 | 24 | class STDIOOutput: 25 | def flush(self_): 26 | pass 27 | 28 | def write(self_, data: str): 29 | if data == '\n': 30 | return 31 | 32 | for r in daf.tracing.TRACE_COLOR_MAP.values(): 33 | data = data.replace(r, "") 34 | 35 | text_output.insert(tk.END, data.replace("\033[0m", "")) 36 | if len(text_output.get()) > 1000: 37 | text_output.delete(0, 500) 38 | 39 | text_output.see(tk.END) 40 | 41 | self._oldstdout = sys.stdout 42 | sys.stdout = STDIOOutput() 43 | -------------------------------------------------------------------------------- /src/daf_gui/tod_extensions/convert.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module implements conversion extensions. 3 | """ 4 | from typing import get_type_hints 5 | from inspect import getmembers 6 | 7 | from tkclasswiz.convert import ObjectInfo, convert_to_object_info 8 | 9 | from daf.misc.instance_track import ObjectReference 10 | from daf.logging.tracing import * 11 | 12 | 13 | 14 | def load_extension_to_object_info(object_, ret: ObjectInfo, *, save_original = False): 15 | if save_original and isinstance(ret, ObjectInfo): 16 | ret.real_object = ObjectReference.from_object(object_) 17 | 18 | # Convert object properties 19 | # This will only be aviable for live objects, since it has no configuration value, 20 | # thus keeping it wouldn't make much sense 21 | if hasattr(object_, "_daf_id"): 22 | property_map = {} 23 | prop: property 24 | for name, prop in getmembers(type(object_), lambda x: isinstance(x, property)): 25 | if name.startswith("_"): # Don't obtain private properties 26 | continue 27 | 28 | try: 29 | return_annotation = get_type_hints(prop.fget).get("return") 30 | property_map[name] = (convert_to_object_info(prop.fget(object_)), return_annotation) 31 | except Exception as exc: 32 | trace( 33 | f"Unable to get property {name} in {object_} when converting to ObjectInfo", 34 | TraceLEVELS.ERROR, 35 | exc 36 | ) 37 | 38 | ret.property_map = property_map 39 | 40 | return ret 41 | -------------------------------------------------------------------------------- /src/daf_gui/tod_extensions/deprecation_notice.py: -------------------------------------------------------------------------------- 1 | """ 2 | Deprecation notices TOD extension. 3 | """ 4 | from tkclasswiz.object_frame.frame_struct import NewObjectFrameStruct 5 | 6 | import ttkbootstrap.dialogs as tkdiag 7 | import ttkbootstrap as ttk 8 | import daf 9 | 10 | 11 | DEPRECATION_NOTICES = { 12 | daf.AutoGUILD: [ 13 | ("Using text (str) on 'include_pattern'", "4.2.0", "AutoGUILD's include_pattern now accepts a BaseLogic object."), 14 | ("'exclude_pattern' parameter", "4.2.0", "Exclusion can now be done with 'include_pattern'") 15 | ], 16 | daf.AutoCHANNEL: [ 17 | ("Using text (str) on 'include_pattern'", "4.2.0", "AutoCHANNEL's include_pattern now accepts a BaseLogic object."), 18 | ("'exclude_pattern' parameter", "4.2.0", "Exclusion can now be done with 'include_pattern'") 19 | ], 20 | daf.TextMESSAGE: [("'start_period' & 'end_period' & 'start_in'", "4.2.0", "Replaced with 'period' parameter")], 21 | daf.VoiceMESSAGE: [("'start_period' & 'end_period' & 'start_in'", "4.2.0", "Replaced with 'period' parameter")], 22 | daf.DirectMESSAGE: [("'start_period' & 'end_period' & 'start_in'", "4.2.0", "Replaced with 'period' parameter")], 23 | } 24 | 25 | 26 | def load_extension(frame: NewObjectFrameStruct, *args, **kwargs): 27 | if len(notices := DEPRECATION_NOTICES.get(frame.class_, [])): 28 | def show_deprecations(): 29 | tkdiag.Messagebox.show_warning( 30 | f"\n{'-'*30}\n".join(f"'{title}' is scheduled for removal in v{version}.\nReason: '{reason}'" for title, version, reason in notices), 31 | "Deprecation notice", 32 | frame 33 | ) 34 | 35 | ttk.Button( 36 | frame.frame_toolbar, 37 | text="Deprecation notices", 38 | bootstyle="dark", 39 | command=show_deprecations 40 | ).pack(side="right") 41 | -------------------------------------------------------------------------------- /src/daf_gui/tod_extensions/help_button.py: -------------------------------------------------------------------------------- 1 | """ 2 | Help button TOD extension. 3 | """ 4 | from tkclasswiz.object_frame.frame_struct import NewObjectFrameStruct 5 | 6 | import ttkbootstrap as ttk 7 | import webbrowser 8 | import _discord 9 | import daf 10 | 11 | 12 | HELP_URLS = { 13 | "daf": f"https://daf.davidhozic.com/en/v{'.'.join(daf.VERSION.split('.')[:2])}.x/?rtd_search={{}}", 14 | "_discord": f"https://docs.pycord.dev/en/v{_discord._version.__version__}/search.html?q={{}}", 15 | } 16 | 17 | 18 | def load_extension(frame: NewObjectFrameStruct, *args, **kwargs): 19 | package = frame.class_.__module__.split(".", 1)[0] 20 | help_url = HELP_URLS.get(package) 21 | if help_url is not None: 22 | def cmd(): 23 | webbrowser.open(help_url.format(frame.get_cls_name(frame.class_))) 24 | 25 | ttk.Button(frame.frame_toolbar, text="Help", command=cmd).pack(side="left") 26 | -------------------------------------------------------------------------------- /src/daf_gui/tod_extensions/live_objects.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implements live object tracking to ObjectInfo. 3 | """ 4 | from collections.abc import Mapping 5 | from tkclasswiz.convert import ObjectInfo 6 | from daf.misc.instance_track import ObjectReference 7 | 8 | 9 | def load_extension_oi(frame: ObjectInfo, *args, **kwargs): 10 | # Additional widgets 11 | frame.real_object: ObjectReference = None 12 | frame.property_map: Mapping[str, "ObjectInfo"] = {} 13 | 14 | def load_extension_oi_eq(self, other: ObjectInfo, result: bool): 15 | return result and self.real_object == other.real_object 16 | 17 | def load_extension_oi_to_object(self, result_object_info: ObjectInfo, **kwargs): 18 | if (old_gui_data := self.old_gui_data) is not None: 19 | # Don't erase the bind to the real object in case this is an edit of an existing ObjectInfo 20 | result_object_info.real_object = old_gui_data.real_object 21 | # Also don't erase any saved properties if received from a live object. 22 | result_object_info.property_map = old_gui_data.property_map 23 | 24 | return result_object_info 25 | 26 | def load_extension_oi_load(self, old_data: ObjectInfo, *args, **kwargs): 27 | if self.old_gui_data is not None: # Preserve the old reference, even if reloading data 28 | self.old_gui_data.real_object = old_data.real_object 29 | self.old_gui_data.property_map = old_data.property_map 30 | -------------------------------------------------------------------------------- /testing/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import sys 3 | import os 4 | 5 | pytest_plugins = [ 6 | "fixtures.main", 7 | ] 8 | 9 | 10 | sys.path.append( 11 | os.path.abspath(os.path.join(os.path.dirname(__file__), "../src")) 12 | ) 13 | -------------------------------------------------------------------------------- /testing/fixtures/__init__.py: -------------------------------------------------------------------------------- 1 | from daf_gui.tod_extensions.loader import register_extensions, register_annotations, register_conversions 2 | register_extensions() 3 | register_annotations() 4 | register_conversions() 5 | -------------------------------------------------------------------------------- /testing/test_remote.py: -------------------------------------------------------------------------------- 1 | """ 2 | Testing module used to test the remote control server. 3 | """ 4 | from daf_gui.connector import RemoteConnectionCLIENT 5 | from daf.misc import instance_track as it 6 | from daf import discord 7 | from test_util import * 8 | 9 | import daf 10 | import pytest 11 | 12 | 13 | @pytest.mark.group_remote 14 | async def test_http(accounts: list[daf.ACCOUNT], guilds: list[discord.Guild]): 15 | client = RemoteConnectionCLIENT("http://127.0.0.1", 8080, "Hello", "World") 16 | await client.initialize(debug=daf.TraceLEVELS.DEPRECATED) 17 | 18 | # Ping 19 | await client._ping() 20 | 21 | # Test get_logger 22 | # assert (await client.get_logger()) is not None 23 | 24 | # Execute method 25 | await client.execute_method( 26 | it.ObjectReference.from_object(accounts[0]), 27 | "add_server", 28 | server=daf.GUILD(guilds[0].id) 29 | ) 30 | new_object = await client.refresh(it.ObjectReference.from_object(accounts[0])) 31 | assert len(new_object.servers) == 1 32 | 33 | await client.execute_method( 34 | it.ObjectReference.from_object(new_object), 35 | "remove_server", 36 | server=it.ObjectReference.from_object(new_object.servers[0]) 37 | ) 38 | new_object = await client.refresh(it.ObjectReference.from_object(accounts[0])) 39 | assert len(new_object.servers) == 0 40 | 41 | # Test object retrieval 42 | new_object = await client.refresh(it.ObjectReference.from_object(accounts[0])) 43 | assert new_object._daf_id == accounts[0]._daf_id 44 | # Test account removal 45 | await client.remove_account(it.ObjectReference.from_object(accounts[0])) 46 | await client.remove_account(it.ObjectReference.from_object(accounts[1])) 47 | # Test account addition 48 | await client.add_account(accounts[0]) 49 | await client.add_account(accounts[1]) 50 | 51 | # Test get_accounts 52 | new_accounts = await client.get_accounts() 53 | for i in range(len(new_accounts)): 54 | compare_objects(new_accounts[i], accounts[i], {"_deleted", "_client", "_daf_id", "_ws_task", "parent"}) 55 | -------------------------------------------------------------------------------- /testing/test_util.py: -------------------------------------------------------------------------------- 1 | """ 2 | Testing helper utilities. 3 | """ 4 | from typing import TypeVar, Callable 5 | from functools import partial 6 | import asyncio 7 | import daf 8 | import inspect 9 | 10 | 11 | T = TypeVar('T') 12 | 13 | 14 | def get_attrs(obj): 15 | slots = set() 16 | slots.update(daf.misc.get_all_slots(type(obj))) 17 | slots.update(getattr(obj, "__dict__", {}.keys())) 18 | return slots 19 | 20 | 21 | def get_value(obj, attr: str, extra_ignore: set=set()): 22 | custom_key_map: dict[T, Callable[[T], tuple]] = { 23 | asyncio.Semaphore: lambda sem: (sem.locked(), sem._value), 24 | daf.discord.Intents: lambda intents: {k: getattr(intents, k) for k in daf.discord.Intents.VALID_FLAGS}, 25 | asyncio.Lock: lambda lock: (lock._locked), 26 | daf.discord.Guild: lambda guild: (guild.name, guild.id) 27 | } 28 | 29 | ignore_attrs = {} 30 | 31 | global_ignores = { 32 | "_sa_class_manager", 33 | "_sa_registry", 34 | "_created_at", 35 | "_id", 36 | "_event_ctrl" 37 | } 38 | 39 | default_key = lambda x: x 40 | value = getattr(obj, attr, None) 41 | key = custom_key_map.get(type(value), default_key) 42 | ignore = ignore_attrs.get(type(obj), set()) 43 | if attr in ignore or attr in global_ignores or attr in extra_ignore: 44 | return None 45 | 46 | return key(value) 47 | 48 | 49 | def compare_objects(obj1, obj2, extra_ignore=set()): 50 | assert type(obj1) is type(obj2) 51 | 52 | if inspect.isclass(obj1) or inspect.isfunction(obj1): 53 | assert obj1 == obj2 54 | return 55 | 56 | if isinstance(obj1, (list, tuple, set)): 57 | list(map(partial(compare_objects, extra_ignore=extra_ignore), obj1, obj2)) 58 | return 59 | 60 | attrs = get_attrs(obj1) 61 | if not attrs: 62 | assert obj1 == obj2 63 | return 64 | 65 | for attr in attrs: 66 | compare_objects( 67 | get_value(obj1, attr, extra_ignore), 68 | get_value(obj2, attr, extra_ignore), 69 | extra_ignore=extra_ignore 70 | ) 71 | -------------------------------------------------------------------------------- /testing/testing123.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidhozic/discord-advertisement-framework/65086cb773279b82f8412d54e8fa7ee686d9608c/testing/testing123.mp3 --------------------------------------------------------------------------------