├── .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
--------------------------------------------------------------------------------