mirror of
https://github.com/Mayuri-Chan/pyrofork.git
synced 2025-12-31 20:54:51 +00:00
Compare commits
No commits in common. "main" and "v2.3.55" have entirely different histories.
247 changed files with 1436 additions and 7078 deletions
21
.github/workflows/build-docs.yml
vendored
21
.github/workflows/build-docs.yml
vendored
|
|
@ -14,25 +14,8 @@ jobs:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- uses: actions/checkout@v4
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Configure
|
|
||||||
run: bash build-docs.sh configure
|
|
||||||
|
|
||||||
- name: Cleanup
|
|
||||||
run: bash build-docs.sh cleanup
|
|
||||||
|
|
||||||
- name: Create virtual environment
|
|
||||||
run: bash build-docs.sh virtualenv
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: bash build-docs.sh build
|
run: bash build-docs.sh
|
||||||
|
|
||||||
- name: Clone gh-pages repository
|
|
||||||
run: bash build-docs.sh clone
|
|
||||||
env:
|
env:
|
||||||
DOCS_KEY: ${{ secrets.DOCS_KEY }}
|
DOCS_KEY: ${{ secrets.DOCS_KEY }}
|
||||||
|
|
||||||
- name: Push changes
|
|
||||||
run: bash build-docs.sh push
|
|
||||||
|
|
|
||||||
2
.github/workflows/python.yml
vendored
2
.github/workflows/python.yml
vendored
|
|
@ -9,7 +9,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest]
|
os: [ubuntu-latest, macos-latest]
|
||||||
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
|
||||||
651
.pylintrc
651
.pylintrc
|
|
@ -1,651 +0,0 @@
|
||||||
[MAIN]
|
|
||||||
|
|
||||||
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
|
||||||
# 3 compatible code, which means that the block might have code that exists
|
|
||||||
# only in one or another interpreter, leading to false positives when analysed.
|
|
||||||
analyse-fallback-blocks=no
|
|
||||||
|
|
||||||
# Clear in-memory caches upon conclusion of linting. Useful if running pylint
|
|
||||||
# in a server-like mode.
|
|
||||||
clear-cache-post-run=no
|
|
||||||
|
|
||||||
# Load and enable all available extensions. Use --list-extensions to see a list
|
|
||||||
# all available extensions.
|
|
||||||
#enable-all-extensions=
|
|
||||||
|
|
||||||
# In error mode, messages with a category besides ERROR or FATAL are
|
|
||||||
# suppressed, and no reports are done by default. Error mode is compatible with
|
|
||||||
# disabling specific errors.
|
|
||||||
#errors-only=
|
|
||||||
|
|
||||||
# Always return a 0 (non-error) status code, even if lint errors are found.
|
|
||||||
# This is primarily useful in continuous integration scripts.
|
|
||||||
#exit-zero=
|
|
||||||
|
|
||||||
# A comma-separated list of package or module names from where C extensions may
|
|
||||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
|
||||||
# run arbitrary code.
|
|
||||||
extension-pkg-allow-list=
|
|
||||||
|
|
||||||
# A comma-separated list of package or module names from where C extensions may
|
|
||||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
|
||||||
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
|
|
||||||
# for backward compatibility.)
|
|
||||||
extension-pkg-whitelist=
|
|
||||||
|
|
||||||
# Return non-zero exit code if any of these messages/categories are detected,
|
|
||||||
# even if score is above --fail-under value. Syntax same as enable. Messages
|
|
||||||
# specified are enabled, while categories only check already-enabled messages.
|
|
||||||
fail-on=
|
|
||||||
|
|
||||||
# Specify a score threshold under which the program will exit with error.
|
|
||||||
fail-under=10
|
|
||||||
|
|
||||||
# Interpret the stdin as a python script, whose filename needs to be passed as
|
|
||||||
# the module_or_package argument.
|
|
||||||
#from-stdin=
|
|
||||||
|
|
||||||
# Files or directories to be skipped. They should be base names, not paths.
|
|
||||||
ignore=CVS
|
|
||||||
|
|
||||||
# Add files or directories matching the regular expressions patterns to the
|
|
||||||
# ignore-list. The regex matches against paths and can be in Posix or Windows
|
|
||||||
# format. Because '\\' represents the directory delimiter on Windows systems,
|
|
||||||
# it can't be used as an escape character.
|
|
||||||
ignore-paths=
|
|
||||||
|
|
||||||
# Files or directories matching the regular expression patterns are skipped.
|
|
||||||
# The regex matches against base names, not paths. The default value ignores
|
|
||||||
# Emacs file locks
|
|
||||||
ignore-patterns=^\.#
|
|
||||||
|
|
||||||
# List of module names for which member attributes should not be checked and
|
|
||||||
# will not be imported (useful for modules/projects where namespaces are
|
|
||||||
# manipulated during runtime and thus existing member attributes cannot be
|
|
||||||
# deduced by static analysis). It supports qualified module names, as well as
|
|
||||||
# Unix pattern matching.
|
|
||||||
ignored-modules=
|
|
||||||
|
|
||||||
# Python code to execute, usually for sys.path manipulation such as
|
|
||||||
# pygtk.require().
|
|
||||||
#init-hook=
|
|
||||||
|
|
||||||
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
|
|
||||||
# number of processors available to use, and will cap the count on Windows to
|
|
||||||
# avoid hangs.
|
|
||||||
jobs=1
|
|
||||||
|
|
||||||
# Control the amount of potential inferred values when inferring a single
|
|
||||||
# object. This can help the performance when dealing with large functions or
|
|
||||||
# complex, nested conditions.
|
|
||||||
limit-inference-results=100
|
|
||||||
|
|
||||||
# List of plugins (as comma separated values of python module names) to load,
|
|
||||||
# usually to register additional checkers.
|
|
||||||
load-plugins=
|
|
||||||
|
|
||||||
# Pickle collected data for later comparisons.
|
|
||||||
persistent=yes
|
|
||||||
|
|
||||||
# Resolve imports to .pyi stubs if available. May reduce no-member messages and
|
|
||||||
# increase not-an-iterable messages.
|
|
||||||
prefer-stubs=no
|
|
||||||
|
|
||||||
# Minimum Python version to use for version dependent checks. Will default to
|
|
||||||
# the version used to run pylint.
|
|
||||||
py-version=3.13
|
|
||||||
|
|
||||||
# Discover python modules and packages in the file system subtree.
|
|
||||||
recursive=no
|
|
||||||
|
|
||||||
# Add paths to the list of the source roots. Supports globbing patterns. The
|
|
||||||
# source root is an absolute path or a path relative to the current working
|
|
||||||
# directory used to determine a package namespace for modules located under the
|
|
||||||
# source root.
|
|
||||||
source-roots=
|
|
||||||
|
|
||||||
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
|
||||||
# user-friendly hints instead of false-positive error messages.
|
|
||||||
suggestion-mode=yes
|
|
||||||
|
|
||||||
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
|
||||||
# active Python interpreter and may run arbitrary code.
|
|
||||||
unsafe-load-any-extension=no
|
|
||||||
|
|
||||||
# In verbose mode, extra non-checker-related info will be displayed.
|
|
||||||
#verbose=
|
|
||||||
|
|
||||||
|
|
||||||
[BASIC]
|
|
||||||
|
|
||||||
# Naming style matching correct argument names.
|
|
||||||
argument-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct argument names. Overrides argument-
|
|
||||||
# naming-style. If left empty, argument names will be checked with the set
|
|
||||||
# naming style.
|
|
||||||
#argument-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct attribute names.
|
|
||||||
attr-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct attribute names. Overrides attr-naming-
|
|
||||||
# style. If left empty, attribute names will be checked with the set naming
|
|
||||||
# style.
|
|
||||||
#attr-rgx=
|
|
||||||
|
|
||||||
# Bad variable names which should always be refused, separated by a comma.
|
|
||||||
bad-names=foo,
|
|
||||||
bar,
|
|
||||||
baz,
|
|
||||||
toto,
|
|
||||||
tutu,
|
|
||||||
tata
|
|
||||||
|
|
||||||
# Bad variable names regexes, separated by a comma. If names match any regex,
|
|
||||||
# they will always be refused
|
|
||||||
bad-names-rgxs=
|
|
||||||
|
|
||||||
# Naming style matching correct class attribute names.
|
|
||||||
class-attribute-naming-style=any
|
|
||||||
|
|
||||||
# Regular expression matching correct class attribute names. Overrides class-
|
|
||||||
# attribute-naming-style. If left empty, class attribute names will be checked
|
|
||||||
# with the set naming style.
|
|
||||||
#class-attribute-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct class constant names.
|
|
||||||
class-const-naming-style=UPPER_CASE
|
|
||||||
|
|
||||||
# Regular expression matching correct class constant names. Overrides class-
|
|
||||||
# const-naming-style. If left empty, class constant names will be checked with
|
|
||||||
# the set naming style.
|
|
||||||
#class-const-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct class names.
|
|
||||||
class-naming-style=PascalCase
|
|
||||||
|
|
||||||
# Regular expression matching correct class names. Overrides class-naming-
|
|
||||||
# style. If left empty, class names will be checked with the set naming style.
|
|
||||||
#class-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct constant names.
|
|
||||||
const-naming-style=UPPER_CASE
|
|
||||||
|
|
||||||
# Regular expression matching correct constant names. Overrides const-naming-
|
|
||||||
# style. If left empty, constant names will be checked with the set naming
|
|
||||||
# style.
|
|
||||||
#const-rgx=
|
|
||||||
|
|
||||||
# Minimum line length for functions/classes that require docstrings, shorter
|
|
||||||
# ones are exempt.
|
|
||||||
docstring-min-length=-1
|
|
||||||
|
|
||||||
# Naming style matching correct function names.
|
|
||||||
function-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct function names. Overrides function-
|
|
||||||
# naming-style. If left empty, function names will be checked with the set
|
|
||||||
# naming style.
|
|
||||||
#function-rgx=
|
|
||||||
|
|
||||||
# Good variable names which should always be accepted, separated by a comma.
|
|
||||||
good-names=i,
|
|
||||||
j,
|
|
||||||
k,
|
|
||||||
ex,
|
|
||||||
Run,
|
|
||||||
_
|
|
||||||
|
|
||||||
# Good variable names regexes, separated by a comma. If names match any regex,
|
|
||||||
# they will always be accepted
|
|
||||||
good-names-rgxs=
|
|
||||||
|
|
||||||
# Include a hint for the correct naming format with invalid-name.
|
|
||||||
include-naming-hint=no
|
|
||||||
|
|
||||||
# Naming style matching correct inline iteration names.
|
|
||||||
inlinevar-naming-style=any
|
|
||||||
|
|
||||||
# Regular expression matching correct inline iteration names. Overrides
|
|
||||||
# inlinevar-naming-style. If left empty, inline iteration names will be checked
|
|
||||||
# with the set naming style.
|
|
||||||
#inlinevar-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct method names.
|
|
||||||
method-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct method names. Overrides method-naming-
|
|
||||||
# style. If left empty, method names will be checked with the set naming style.
|
|
||||||
#method-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct module names.
|
|
||||||
module-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct module names. Overrides module-naming-
|
|
||||||
# style. If left empty, module names will be checked with the set naming style.
|
|
||||||
#module-rgx=
|
|
||||||
|
|
||||||
# Colon-delimited sets of names that determine each other's naming style when
|
|
||||||
# the name regexes allow several styles.
|
|
||||||
name-group=
|
|
||||||
|
|
||||||
# Regular expression which should only match function or class names that do
|
|
||||||
# not require a docstring.
|
|
||||||
no-docstring-rgx=^_
|
|
||||||
|
|
||||||
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
|
||||||
# to this list to register other decorators that produce valid properties.
|
|
||||||
# These decorators are taken in consideration only for invalid-name.
|
|
||||||
property-classes=abc.abstractproperty
|
|
||||||
|
|
||||||
# Regular expression matching correct type alias names. If left empty, type
|
|
||||||
# alias names will be checked with the set naming style.
|
|
||||||
#typealias-rgx=
|
|
||||||
|
|
||||||
# Regular expression matching correct type variable names. If left empty, type
|
|
||||||
# variable names will be checked with the set naming style.
|
|
||||||
#typevar-rgx=
|
|
||||||
|
|
||||||
# Naming style matching correct variable names.
|
|
||||||
variable-naming-style=snake_case
|
|
||||||
|
|
||||||
# Regular expression matching correct variable names. Overrides variable-
|
|
||||||
# naming-style. If left empty, variable names will be checked with the set
|
|
||||||
# naming style.
|
|
||||||
#variable-rgx=
|
|
||||||
|
|
||||||
|
|
||||||
[CLASSES]
|
|
||||||
|
|
||||||
# Warn about protected attribute access inside special methods
|
|
||||||
check-protected-access-in-special-methods=no
|
|
||||||
|
|
||||||
# List of method names used to declare (i.e. assign) instance attributes.
|
|
||||||
defining-attr-methods=__init__,
|
|
||||||
__new__,
|
|
||||||
setUp,
|
|
||||||
asyncSetUp,
|
|
||||||
__post_init__
|
|
||||||
|
|
||||||
# List of member names, which should be excluded from the protected access
|
|
||||||
# warning.
|
|
||||||
exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit
|
|
||||||
|
|
||||||
# List of valid names for the first argument in a class method.
|
|
||||||
valid-classmethod-first-arg=cls
|
|
||||||
|
|
||||||
# List of valid names for the first argument in a metaclass class method.
|
|
||||||
valid-metaclass-classmethod-first-arg=mcs
|
|
||||||
|
|
||||||
|
|
||||||
[DESIGN]
|
|
||||||
|
|
||||||
# List of regular expressions of class ancestor names to ignore when counting
|
|
||||||
# public methods (see R0903)
|
|
||||||
exclude-too-few-public-methods=
|
|
||||||
|
|
||||||
# List of qualified class names to ignore when counting class parents (see
|
|
||||||
# R0901)
|
|
||||||
ignored-parents=
|
|
||||||
|
|
||||||
# Maximum number of arguments for function / method.
|
|
||||||
max-args=5
|
|
||||||
|
|
||||||
# Maximum number of attributes for a class (see R0902).
|
|
||||||
max-attributes=7
|
|
||||||
|
|
||||||
# Maximum number of boolean expressions in an if statement (see R0916).
|
|
||||||
max-bool-expr=5
|
|
||||||
|
|
||||||
# Maximum number of branch for function / method body.
|
|
||||||
max-branches=12
|
|
||||||
|
|
||||||
# Maximum number of locals for function / method body.
|
|
||||||
max-locals=15
|
|
||||||
|
|
||||||
# Maximum number of parents for a class (see R0901).
|
|
||||||
max-parents=7
|
|
||||||
|
|
||||||
# Maximum number of positional arguments for function / method.
|
|
||||||
max-positional-arguments=5
|
|
||||||
|
|
||||||
# Maximum number of public methods for a class (see R0904).
|
|
||||||
max-public-methods=20
|
|
||||||
|
|
||||||
# Maximum number of return / yield for function / method body.
|
|
||||||
max-returns=6
|
|
||||||
|
|
||||||
# Maximum number of statements in function / method body.
|
|
||||||
max-statements=50
|
|
||||||
|
|
||||||
# Minimum number of public methods for a class (see R0903).
|
|
||||||
min-public-methods=2
|
|
||||||
|
|
||||||
|
|
||||||
[EXCEPTIONS]
|
|
||||||
|
|
||||||
# Exceptions that will emit a warning when caught.
|
|
||||||
overgeneral-exceptions=builtins.BaseException,builtins.Exception
|
|
||||||
|
|
||||||
|
|
||||||
[FORMAT]
|
|
||||||
|
|
||||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
|
||||||
expected-line-ending-format=
|
|
||||||
|
|
||||||
# Regexp for a line that is allowed to be longer than the limit.
|
|
||||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
|
||||||
|
|
||||||
# Number of spaces of indent required inside a hanging or continued line.
|
|
||||||
indent-after-paren=4
|
|
||||||
|
|
||||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
|
||||||
# tab).
|
|
||||||
indent-string=' '
|
|
||||||
|
|
||||||
# Maximum number of characters on a single line.
|
|
||||||
max-line-length=100
|
|
||||||
|
|
||||||
# Maximum number of lines in a module.
|
|
||||||
max-module-lines=1000
|
|
||||||
|
|
||||||
# Allow the body of a class to be on the same line as the declaration if body
|
|
||||||
# contains single statement.
|
|
||||||
single-line-class-stmt=no
|
|
||||||
|
|
||||||
# Allow the body of an if to be on the same line as the test if there is no
|
|
||||||
# else.
|
|
||||||
single-line-if-stmt=no
|
|
||||||
|
|
||||||
|
|
||||||
[IMPORTS]
|
|
||||||
|
|
||||||
# List of modules that can be imported at any level, not just the top level
|
|
||||||
# one.
|
|
||||||
allow-any-import-level=
|
|
||||||
|
|
||||||
# Allow explicit reexports by alias from a package __init__.
|
|
||||||
allow-reexport-from-package=no
|
|
||||||
|
|
||||||
# Allow wildcard imports from modules that define __all__.
|
|
||||||
allow-wildcard-with-all=no
|
|
||||||
|
|
||||||
# Deprecated modules which should not be used, separated by a comma.
|
|
||||||
deprecated-modules=
|
|
||||||
|
|
||||||
# Output a graph (.gv or any supported image format) of external dependencies
|
|
||||||
# to the given file (report RP0402 must not be disabled).
|
|
||||||
ext-import-graph=
|
|
||||||
|
|
||||||
# Output a graph (.gv or any supported image format) of all (i.e. internal and
|
|
||||||
# external) dependencies to the given file (report RP0402 must not be
|
|
||||||
# disabled).
|
|
||||||
import-graph=
|
|
||||||
|
|
||||||
# Output a graph (.gv or any supported image format) of internal dependencies
|
|
||||||
# to the given file (report RP0402 must not be disabled).
|
|
||||||
int-import-graph=
|
|
||||||
|
|
||||||
# Force import order to recognize a module as part of the standard
|
|
||||||
# compatibility libraries.
|
|
||||||
known-standard-library=
|
|
||||||
|
|
||||||
# Force import order to recognize a module as part of a third party library.
|
|
||||||
known-third-party=enchant
|
|
||||||
|
|
||||||
# Couples of modules and preferred modules, separated by a comma.
|
|
||||||
preferred-modules=
|
|
||||||
|
|
||||||
|
|
||||||
[LOGGING]
|
|
||||||
|
|
||||||
# The type of string formatting that logging methods do. `old` means using %
|
|
||||||
# formatting, `new` is for `{}` formatting.
|
|
||||||
logging-format-style=old
|
|
||||||
|
|
||||||
# Logging modules to check that the string format arguments are in logging
|
|
||||||
# function parameter format.
|
|
||||||
logging-modules=logging
|
|
||||||
|
|
||||||
|
|
||||||
[MESSAGES CONTROL]
|
|
||||||
|
|
||||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
|
||||||
# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
|
|
||||||
# UNDEFINED.
|
|
||||||
confidence=HIGH,
|
|
||||||
CONTROL_FLOW,
|
|
||||||
INFERENCE,
|
|
||||||
INFERENCE_FAILURE,
|
|
||||||
UNDEFINED
|
|
||||||
|
|
||||||
# Disable the message, report, category or checker with the given id(s). You
|
|
||||||
# can either give multiple identifiers separated by comma (,) or put this
|
|
||||||
# option multiple times (only on the command line, not in the configuration
|
|
||||||
# file where it should appear only once). You can also use "--disable=all" to
|
|
||||||
# disable everything first and then re-enable specific checks. For example, if
|
|
||||||
# you want to run only the similarities checker, you can use "--disable=all
|
|
||||||
# --enable=similarities". If you want to run only the classes checker, but have
|
|
||||||
# no Warning level messages displayed, use "--disable=all --enable=classes
|
|
||||||
# --disable=W".
|
|
||||||
disable=raw-checker-failed,
|
|
||||||
bad-inline-option,
|
|
||||||
locally-disabled,
|
|
||||||
file-ignored,
|
|
||||||
suppressed-message,
|
|
||||||
useless-suppression,
|
|
||||||
deprecated-pragma,
|
|
||||||
use-implicit-booleaness-not-comparison-to-string,
|
|
||||||
use-implicit-booleaness-not-comparison-to-zero,
|
|
||||||
use-symbolic-message-instead,
|
|
||||||
missing-module-docstring,
|
|
||||||
missing-class-docstring,
|
|
||||||
missing-function-docstring,
|
|
||||||
redefined-builtin
|
|
||||||
|
|
||||||
# Enable the message, report, category or checker with the given id(s). You can
|
|
||||||
# either give multiple identifier separated by comma (,) or put this option
|
|
||||||
# multiple time (only on the command line, not in the configuration file where
|
|
||||||
# it should appear only once). See also the "--disable" option for examples.
|
|
||||||
enable=
|
|
||||||
|
|
||||||
|
|
||||||
[METHOD_ARGS]
|
|
||||||
|
|
||||||
# List of qualified names (i.e., library.method) which require a timeout
|
|
||||||
# parameter e.g. 'requests.api.get,requests.api.post'
|
|
||||||
timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request
|
|
||||||
|
|
||||||
|
|
||||||
[MISCELLANEOUS]
|
|
||||||
|
|
||||||
# List of note tags to take in consideration, separated by a comma.
|
|
||||||
notes=FIXME,
|
|
||||||
XXX,
|
|
||||||
TODO
|
|
||||||
|
|
||||||
# Regular expression of note tags to take in consideration.
|
|
||||||
notes-rgx=
|
|
||||||
|
|
||||||
|
|
||||||
[REFACTORING]
|
|
||||||
|
|
||||||
# Maximum number of nested blocks for function / method body
|
|
||||||
max-nested-blocks=5
|
|
||||||
|
|
||||||
# Complete name of functions that never returns. When checking for
|
|
||||||
# inconsistent-return-statements if a never returning function is called then
|
|
||||||
# it will be considered as an explicit return statement and no message will be
|
|
||||||
# printed.
|
|
||||||
never-returning-functions=sys.exit,argparse.parse_error
|
|
||||||
|
|
||||||
# Let 'consider-using-join' be raised when the separator to join on would be
|
|
||||||
# non-empty (resulting in expected fixes of the type: ``"- " + " -
|
|
||||||
# ".join(items)``)
|
|
||||||
suggest-join-with-non-empty-separator=yes
|
|
||||||
|
|
||||||
|
|
||||||
[REPORTS]
|
|
||||||
|
|
||||||
# Python expression which should return a score less than or equal to 10. You
|
|
||||||
# have access to the variables 'fatal', 'error', 'warning', 'refactor',
|
|
||||||
# 'convention', and 'info' which contain the number of messages in each
|
|
||||||
# category, as well as 'statement' which is the total number of statements
|
|
||||||
# analyzed. This score is used by the global evaluation report (RP0004).
|
|
||||||
evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
|
|
||||||
|
|
||||||
# Template used to display messages. This is a python new-style format string
|
|
||||||
# used to format the message information. See doc for all details.
|
|
||||||
msg-template=
|
|
||||||
|
|
||||||
# Set the output format. Available formats are: 'text', 'parseable',
|
|
||||||
# 'colorized', 'json2' (improved json format), 'json' (old json format), msvs
|
|
||||||
# (visual studio) and 'github' (GitHub actions). You can also give a reporter
|
|
||||||
# class, e.g. mypackage.mymodule.MyReporterClass.
|
|
||||||
#output-format=
|
|
||||||
|
|
||||||
# Tells whether to display a full report or only the messages.
|
|
||||||
reports=no
|
|
||||||
|
|
||||||
# Activate the evaluation score.
|
|
||||||
score=yes
|
|
||||||
|
|
||||||
|
|
||||||
[SIMILARITIES]
|
|
||||||
|
|
||||||
# Comments are removed from the similarity computation
|
|
||||||
ignore-comments=yes
|
|
||||||
|
|
||||||
# Docstrings are removed from the similarity computation
|
|
||||||
ignore-docstrings=yes
|
|
||||||
|
|
||||||
# Imports are removed from the similarity computation
|
|
||||||
ignore-imports=yes
|
|
||||||
|
|
||||||
# Signatures are removed from the similarity computation
|
|
||||||
ignore-signatures=yes
|
|
||||||
|
|
||||||
# Minimum lines number of a similarity.
|
|
||||||
min-similarity-lines=4
|
|
||||||
|
|
||||||
|
|
||||||
[SPELLING]
|
|
||||||
|
|
||||||
# Limits count of emitted suggestions for spelling mistakes.
|
|
||||||
max-spelling-suggestions=4
|
|
||||||
|
|
||||||
# Spelling dictionary name. No available dictionaries : You need to install
|
|
||||||
# both the python package and the system dependency for enchant to work.
|
|
||||||
spelling-dict=
|
|
||||||
|
|
||||||
# List of comma separated words that should be considered directives if they
|
|
||||||
# appear at the beginning of a comment and should not be checked.
|
|
||||||
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
|
|
||||||
|
|
||||||
# List of comma separated words that should not be checked.
|
|
||||||
spelling-ignore-words=
|
|
||||||
|
|
||||||
# A path to a file that contains the private dictionary; one word per line.
|
|
||||||
spelling-private-dict-file=
|
|
||||||
|
|
||||||
# Tells whether to store unknown words to the private dictionary (see the
|
|
||||||
# --spelling-private-dict-file option) instead of raising a message.
|
|
||||||
spelling-store-unknown-words=no
|
|
||||||
|
|
||||||
|
|
||||||
[STRING]
|
|
||||||
|
|
||||||
# This flag controls whether inconsistent-quotes generates a warning when the
|
|
||||||
# character used as a quote delimiter is used inconsistently within a module.
|
|
||||||
check-quote-consistency=no
|
|
||||||
|
|
||||||
# This flag controls whether the implicit-str-concat should generate a warning
|
|
||||||
# on implicit string concatenation in sequences defined over several lines.
|
|
||||||
check-str-concat-over-line-jumps=no
|
|
||||||
|
|
||||||
|
|
||||||
[TYPECHECK]
|
|
||||||
|
|
||||||
# List of decorators that produce context managers, such as
|
|
||||||
# contextlib.contextmanager. Add to this list to register other decorators that
|
|
||||||
# produce valid context managers.
|
|
||||||
contextmanager-decorators=contextlib.contextmanager
|
|
||||||
|
|
||||||
# List of members which are set dynamically and missed by pylint inference
|
|
||||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
|
||||||
# expressions are accepted.
|
|
||||||
generated-members=
|
|
||||||
|
|
||||||
# Tells whether to warn about missing members when the owner of the attribute
|
|
||||||
# is inferred to be None.
|
|
||||||
ignore-none=yes
|
|
||||||
|
|
||||||
# This flag controls whether pylint should warn about no-member and similar
|
|
||||||
# checks whenever an opaque object is returned when inferring. The inference
|
|
||||||
# can return multiple potential results while evaluating a Python object, but
|
|
||||||
# some branches might not be evaluated, which results in partial inference. In
|
|
||||||
# that case, it might be useful to still emit no-member and other checks for
|
|
||||||
# the rest of the inferred objects.
|
|
||||||
ignore-on-opaque-inference=yes
|
|
||||||
|
|
||||||
# List of symbolic message names to ignore for Mixin members.
|
|
||||||
ignored-checks-for-mixins=no-member,
|
|
||||||
not-async-context-manager,
|
|
||||||
not-context-manager,
|
|
||||||
attribute-defined-outside-init
|
|
||||||
|
|
||||||
# List of class names for which member attributes should not be checked (useful
|
|
||||||
# for classes with dynamically set attributes). This supports the use of
|
|
||||||
# qualified names.
|
|
||||||
ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
|
|
||||||
|
|
||||||
# Show a hint with possible names when a member name was not found. The aspect
|
|
||||||
# of finding the hint is based on edit distance.
|
|
||||||
missing-member-hint=yes
|
|
||||||
|
|
||||||
# The minimum edit distance a name should have in order to be considered a
|
|
||||||
# similar match for a missing member name.
|
|
||||||
missing-member-hint-distance=1
|
|
||||||
|
|
||||||
# The total number of similar names that should be taken in consideration when
|
|
||||||
# showing a hint for a missing member.
|
|
||||||
missing-member-max-choices=1
|
|
||||||
|
|
||||||
# Regex pattern to define which classes are considered mixins.
|
|
||||||
mixin-class-rgx=.*[Mm]ixin
|
|
||||||
|
|
||||||
# List of decorators that change the signature of a decorated function.
|
|
||||||
signature-mutators=
|
|
||||||
|
|
||||||
|
|
||||||
[VARIABLES]
|
|
||||||
|
|
||||||
# List of additional names supposed to be defined in builtins. Remember that
|
|
||||||
# you should avoid defining new builtins when possible.
|
|
||||||
additional-builtins=
|
|
||||||
|
|
||||||
# Tells whether unused global variables should be treated as a violation.
|
|
||||||
allow-global-unused-variables=yes
|
|
||||||
|
|
||||||
# List of names allowed to shadow builtins
|
|
||||||
allowed-redefined-builtins=
|
|
||||||
|
|
||||||
# List of strings which can identify a callback function by name. A callback
|
|
||||||
# name must start or end with one of those strings.
|
|
||||||
callbacks=cb_,
|
|
||||||
_cb
|
|
||||||
|
|
||||||
# A regular expression matching the name of dummy variables (i.e. expected to
|
|
||||||
# not be used).
|
|
||||||
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
|
||||||
|
|
||||||
# Argument names that match this expression will be ignored.
|
|
||||||
ignored-argument-names=_.*|^ignored_|^unused_
|
|
||||||
|
|
||||||
# Tells whether we should check for unused import in __init__ files.
|
|
||||||
init-import=no
|
|
||||||
|
|
||||||
# List of qualified module names which can have objects that can redefine
|
|
||||||
# builtins.
|
|
||||||
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
Homepage
|
Homepage
|
||||||
</a>
|
</a>
|
||||||
•
|
•
|
||||||
<a href="https://pyrofork.wulan17.dev">
|
<a href="https://pyrofork.wulan17.top">
|
||||||
Documentation
|
Documentation
|
||||||
</a>
|
</a>
|
||||||
•
|
•
|
||||||
|
|
@ -44,7 +44,7 @@ async def hello(client, message):
|
||||||
app.run()
|
app.run()
|
||||||
```
|
```
|
||||||
|
|
||||||
**Pyrofork** is a modern, elegant and asynchronous [MTProto API](https://pyrofork.wulan17.dev/main/topics/mtproto-vs-botapi)
|
**Pyrofork** is a modern, elegant and asynchronous [MTProto API](https://pyrofork.wulan17.top/main/topics/mtproto-vs-botapi)
|
||||||
framework. It enables you to easily interact with the main Telegram API through a user account (custom client) or a bot
|
framework. It enables you to easily interact with the main Telegram API through a user account (custom client) or a bot
|
||||||
identity (bot API alternative) using Python.
|
identity (bot API alternative) using Python.
|
||||||
|
|
||||||
|
|
@ -72,6 +72,6 @@ pip3 install pyrofork
|
||||||
|
|
||||||
### Resources
|
### Resources
|
||||||
|
|
||||||
- Check out the docs at https://pyrofork.wulan17.dev to learn more about Pyrofork, get started right
|
- Check out the docs at https://pyrofork.wulan17.top to learn more about Pyrofork, get started right
|
||||||
away and discover more in-depth material for building your client applications.
|
away and discover more in-depth material for building your client applications.
|
||||||
- Join the official group at https://t.me/MayuriChan_Chat and stay tuned for news, updates and announcements.
|
- Join the official group at https://t.me/MayuriChan_Chat and stay tuned for news, updates and announcements.
|
||||||
|
|
|
||||||
115
build-docs.sh
115
build-docs.sh
|
|
@ -1,87 +1,42 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
export DOCS_KEY
|
||||||
|
VENV="$(pwd)"/venv
|
||||||
|
export VENV
|
||||||
|
|
||||||
# Check if config.sh exists
|
if [[ "$(echo "$GITHUB_REF" | cut -d '/' -f "1 2")" == "refs/tags" ]]; then
|
||||||
if [ -f config.sh ]; then
|
branch="main"
|
||||||
source config.sh
|
elif [[ "$GITHUB_REF" == "refs/heads/staging" ]]; then
|
||||||
fi
|
branch="staging"
|
||||||
|
else
|
||||||
function parse_parameters() {
|
b="$(echo "$GITHUB_REF" | cut -d '/' -f '3 4')"
|
||||||
while (($#)); do
|
if [[ $(echo "$b" | cut -d '/' -f 1 ) == "dev" ]]; then
|
||||||
case $1 in
|
b="$(echo "$b" | cut -d '/' -f 2)"
|
||||||
all | configure | cleanup | virtualenv | build | clone | push ) action=$1 ;;
|
if [[ "$b" =~ ^[0-9]\.[0-9]\.x ]]; then
|
||||||
*) exit 33 ;;
|
branch="$b"
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
function do_configure() {
|
|
||||||
echo "#!/bin/bash" > config.sh
|
|
||||||
echo "export VENV=\"$(pwd)/venv\"" >> config.sh
|
|
||||||
|
|
||||||
if [[ "$(echo "$GITHUB_REF" | cut -d '/' -f "1 2")" == "refs/tags" ]]; then
|
|
||||||
echo "export BRANCH=\"main\"" >> config.sh
|
|
||||||
elif [[ "$GITHUB_REF" == "refs/heads/staging" ]]; then
|
|
||||||
echo "export BRANCH=\"staging\"" >> config.sh
|
|
||||||
else
|
|
||||||
b="$(echo "$GITHUB_REF" | cut -d '/' -f '3 4')"
|
|
||||||
if [[ $(echo "$b" | cut -d '/' -f 1 ) == "dev" ]]; then
|
|
||||||
b="$(echo "$b" | cut -d '/' -f 2)"
|
|
||||||
if [[ "$b" =~ ^[0-9]\.[0-9]\.x ]]; then
|
|
||||||
echo "export BRANCH=\"$b\"" >> config.sh
|
|
||||||
else
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
chmod +x config.sh
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
function do_cleanup() {
|
make clean
|
||||||
make clean
|
make clean-docs
|
||||||
make clean-docs
|
make venv
|
||||||
}
|
make api
|
||||||
|
"$VENV"/bin/pip install -e '.[docs]'
|
||||||
function do_virtualenv() {
|
cd compiler/docs || exit 1 && "$VENV"/bin/python compiler.py
|
||||||
make venv
|
cd ../.. || exit 1
|
||||||
make api
|
"$VENV"/bin/sphinx-build -b html "docs/source" "docs/build/html" -j auto
|
||||||
"$VENV"/bin/pip install -e '.[docs]'
|
git clone https://wulan17:"$DOCS_KEY"@github.com/Mayuri-Chan/pyrofork-docs.git
|
||||||
}
|
cd pyrofork-docs || exit 1
|
||||||
|
mkdir -p "$branch"
|
||||||
function do_build() {
|
cd "$branch" || exit 1
|
||||||
cd compiler/docs || exit 1 && "$VENV"/bin/python compiler.py
|
rm -rf _includes api genindex.html intro py-modindex.html sitemap.xml support.html topics _static faq index.html objects.inv searchindex.js start telegram
|
||||||
cd ../.. || exit 1
|
cp -r ../../docs/build/html/* .
|
||||||
"$VENV"/bin/sphinx-build -b html "docs/source" "docs/build/html" -j auto
|
git config --local user.name "Mayuri-Chan"
|
||||||
}
|
git config --local user.email "mayuri@mayuri.my.id"
|
||||||
|
git add --all
|
||||||
function do_clone() {
|
git commit -a -m "docs: $branch: Update docs $(date '+%Y-%m-%d | %H:%m:%S %p %Z')" --signoff
|
||||||
git clone https://wulan17:"$DOCS_KEY"@github.com/Mayuri-Chan/pyrofork-docs.git
|
git push -u origin --all
|
||||||
}
|
|
||||||
|
|
||||||
function do_push() {
|
|
||||||
cd pyrofork-docs || exit 1
|
|
||||||
mkdir -p "$BRANCH"
|
|
||||||
cd "$BRANCH" || exit 1
|
|
||||||
rm -rf _includes api genindex.html intro py-modindex.html sitemap.xml support.html topics _static faq index.html objects.inv searchindex.js start telegram
|
|
||||||
cp -r ../../docs/build/html/* .
|
|
||||||
git config --local user.name "Mayuri-Chan"
|
|
||||||
git config --local user.email "mayuri@mayuri.my.id"
|
|
||||||
git add --all
|
|
||||||
git commit -a -m "docs: $BRANCH: Update docs $(date '+%Y-%m-%d | %H:%m:%S %p %Z')" --signoff
|
|
||||||
git push -u origin --all
|
|
||||||
}
|
|
||||||
|
|
||||||
function do_all() {
|
|
||||||
do_configure
|
|
||||||
source config.sh
|
|
||||||
do_cleanup
|
|
||||||
do_virtualenv
|
|
||||||
do_build
|
|
||||||
do_clone
|
|
||||||
do_push
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_parameters "$@"
|
|
||||||
do_"${action:=all}"
|
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ def get_type_hint(type: str) -> str:
|
||||||
return f"Optional[{type}] = None" if is_flag else type
|
return f"Optional[{type}] = None" if is_flag else type
|
||||||
else:
|
else:
|
||||||
ns, name = type.split(".") if "." in type else ("", type)
|
ns, name = type.split(".") if "." in type else ("", type)
|
||||||
type = '"raw.base.' + ".".join([ns, name]).strip(".") + '"'
|
type = f'"raw.base.' + ".".join([ns, name]).strip(".") + '"'
|
||||||
|
|
||||||
return f'{type}{" = None" if is_flag else ""}'
|
return f'{type}{" = None" if is_flag else ""}'
|
||||||
|
|
||||||
|
|
@ -430,11 +430,11 @@ def start(format: bool = False):
|
||||||
if function_docs:
|
if function_docs:
|
||||||
docstring += function_docs["desc"] + "\n"
|
docstring += function_docs["desc"] + "\n"
|
||||||
else:
|
else:
|
||||||
docstring += "Telegram API function."
|
docstring += f"Telegram API function."
|
||||||
|
|
||||||
docstring += f"\n\n Details:\n - Layer: ``{layer}``\n - ID: ``{c.id[2:].upper()}``\n\n"
|
docstring += f"\n\n Details:\n - Layer: ``{layer}``\n - ID: ``{c.id[2:].upper()}``\n\n"
|
||||||
docstring += " Parameters:\n " + \
|
docstring += f" Parameters:\n " + \
|
||||||
("\n ".join(docstring_args) if docstring_args else "No parameters required.\n")
|
(f"\n ".join(docstring_args) if docstring_args else "No parameters required.\n")
|
||||||
|
|
||||||
if c.section == "functions":
|
if c.section == "functions":
|
||||||
docstring += "\n Returns:\n " + get_docstring_arg_type(c.qualtype)
|
docstring += "\n Returns:\n " + get_docstring_arg_type(c.qualtype)
|
||||||
|
|
@ -442,12 +442,12 @@ def start(format: bool = False):
|
||||||
references, count = get_references(c.qualname, "constructors")
|
references, count = get_references(c.qualname, "constructors")
|
||||||
|
|
||||||
if references:
|
if references:
|
||||||
docstring += "\n Functions:\n This object can be returned by " \
|
docstring += f"\n Functions:\n This object can be returned by " \
|
||||||
f"{count} function{'s' if count > 1 else ''}.\n\n" \
|
f"{count} function{'s' if count > 1 else ''}.\n\n" \
|
||||||
" .. currentmodule:: pyrogram.raw.functions\n\n" \
|
f" .. currentmodule:: pyrogram.raw.functions\n\n" \
|
||||||
" .. autosummary::\n" \
|
f" .. autosummary::\n" \
|
||||||
" :nosignatures:\n\n" \
|
f" :nosignatures:\n\n" \
|
||||||
" " + references
|
f" " + references
|
||||||
|
|
||||||
write_types = read_types = "" if c.has_flags else "# No flags\n "
|
write_types = read_types = "" if c.has_flags else "# No flags\n "
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -20,4 +20,4 @@ class {name}: # type: ignore
|
||||||
raise TypeError("Base types can only be used for type checking purposes: "
|
raise TypeError("Base types can only be used for type checking purposes: "
|
||||||
"you tried to use a base type instance as argument, "
|
"you tried to use a base type instance as argument, "
|
||||||
"but you need to instantiate one of its constructors instead. "
|
"but you need to instantiate one of its constructors instead. "
|
||||||
"More info: https://pyrofork.wulan17.dev/telegram/base/{doc_name}")
|
"More info: https://pyrofork.wulan17.top/telegram/base/{doc_name}")
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,6 @@ def pyrogram_api():
|
||||||
stop_transmission
|
stop_transmission
|
||||||
export_session_string
|
export_session_string
|
||||||
set_parse_mode
|
set_parse_mode
|
||||||
ping
|
|
||||||
""",
|
""",
|
||||||
conversation="""
|
conversation="""
|
||||||
Conversation
|
Conversation
|
||||||
|
|
@ -165,7 +164,6 @@ def pyrogram_api():
|
||||||
""",
|
""",
|
||||||
messages="""
|
messages="""
|
||||||
Messages
|
Messages
|
||||||
add_task_to_todo
|
|
||||||
send_message
|
send_message
|
||||||
forward_media_group
|
forward_media_group
|
||||||
forward_messages
|
forward_messages
|
||||||
|
|
@ -175,7 +173,6 @@ def pyrogram_api():
|
||||||
send_audio
|
send_audio
|
||||||
send_document
|
send_document
|
||||||
send_sticker
|
send_sticker
|
||||||
send_todo
|
|
||||||
send_video
|
send_video
|
||||||
send_animation
|
send_animation
|
||||||
send_voice
|
send_voice
|
||||||
|
|
@ -187,7 +184,6 @@ def pyrogram_api():
|
||||||
send_contact
|
send_contact
|
||||||
send_cached_media
|
send_cached_media
|
||||||
send_reaction
|
send_reaction
|
||||||
set_todo_tasks_completion
|
|
||||||
edit_message_text
|
edit_message_text
|
||||||
edit_message_caption
|
edit_message_caption
|
||||||
edit_message_media
|
edit_message_media
|
||||||
|
|
@ -224,10 +220,8 @@ def pyrogram_api():
|
||||||
get_discussion_replies
|
get_discussion_replies
|
||||||
get_discussion_replies_count
|
get_discussion_replies_count
|
||||||
get_custom_emoji_stickers
|
get_custom_emoji_stickers
|
||||||
transcribe_audio
|
|
||||||
translate_message_text
|
translate_message_text
|
||||||
start_bot
|
start_bot
|
||||||
delete_chat_history
|
|
||||||
""",
|
""",
|
||||||
chats="""
|
chats="""
|
||||||
Chats
|
Chats
|
||||||
|
|
@ -258,7 +252,6 @@ def pyrogram_api():
|
||||||
get_folders
|
get_folders
|
||||||
get_forum_topics
|
get_forum_topics
|
||||||
get_forum_topics_by_id
|
get_forum_topics_by_id
|
||||||
get_forum_topics_count
|
|
||||||
set_chat_username
|
set_chat_username
|
||||||
archive_chats
|
archive_chats
|
||||||
unarchive_chats
|
unarchive_chats
|
||||||
|
|
@ -285,7 +278,6 @@ def pyrogram_api():
|
||||||
hide_general_topic
|
hide_general_topic
|
||||||
reopen_forum_topic
|
reopen_forum_topic
|
||||||
reopen_general_topic
|
reopen_general_topic
|
||||||
transfer_chat_ownership
|
|
||||||
unhide_general_topic
|
unhide_general_topic
|
||||||
update_color
|
update_color
|
||||||
update_folder
|
update_folder
|
||||||
|
|
@ -364,29 +356,20 @@ def pyrogram_api():
|
||||||
get_stars_transactions
|
get_stars_transactions
|
||||||
get_stars_transactions_by_id
|
get_stars_transactions_by_id
|
||||||
get_available_gifts
|
get_available_gifts
|
||||||
get_upgraded_gift
|
get_user_gifts_count
|
||||||
get_chat_gifts_count
|
get_user_gifts
|
||||||
get_chat_gifts
|
|
||||||
hide_gift
|
hide_gift
|
||||||
refund_star_payment
|
refund_star_payment
|
||||||
search_gifts_for_resale
|
|
||||||
send_invoice
|
send_invoice
|
||||||
send_paid_media
|
send_paid_media
|
||||||
send_paid_reaction
|
send_paid_reaction
|
||||||
send_payment_form
|
send_payment_form
|
||||||
send_gift
|
send_gift
|
||||||
send_resold_gift
|
|
||||||
set_gift_resale_price
|
|
||||||
set_pinned_gifts
|
|
||||||
show_gift
|
show_gift
|
||||||
transfer_gift
|
transfer_gift
|
||||||
upgrade_gift
|
upgrade_gift
|
||||||
get_stars_balance
|
get_stars_balance
|
||||||
""",
|
""",
|
||||||
phone="""
|
|
||||||
Phone
|
|
||||||
get_call_members
|
|
||||||
""",
|
|
||||||
password="""
|
password="""
|
||||||
Password
|
Password
|
||||||
enable_cloud_password
|
enable_cloud_password
|
||||||
|
|
@ -415,17 +398,12 @@ def pyrogram_api():
|
||||||
set_bot_info
|
set_bot_info
|
||||||
get_collectible_item_info
|
get_collectible_item_info
|
||||||
get_owned_bots
|
get_owned_bots
|
||||||
get_similar_bots
|
|
||||||
""",
|
""",
|
||||||
business="""
|
business="""
|
||||||
Telegram Business
|
Telegram Business
|
||||||
answer_pre_checkout_query
|
answer_pre_checkout_query
|
||||||
answer_shipping_query
|
answer_shipping_query
|
||||||
delete_business_messages
|
|
||||||
get_business_connection
|
get_business_connection
|
||||||
get_business_account_gifts
|
|
||||||
get_business_account_star_balance
|
|
||||||
transfer_business_account_stars
|
|
||||||
""",
|
""",
|
||||||
authorization="""
|
authorization="""
|
||||||
Authorization
|
Authorization
|
||||||
|
|
@ -437,11 +415,12 @@ def pyrogram_api():
|
||||||
resend_code
|
resend_code
|
||||||
sign_in
|
sign_in
|
||||||
sign_in_bot
|
sign_in_bot
|
||||||
sign_in_qrcode
|
sign_up
|
||||||
get_password_hint
|
get_password_hint
|
||||||
check_password
|
check_password
|
||||||
send_recovery_code
|
send_recovery_code
|
||||||
recover_password
|
recover_password
|
||||||
|
accept_terms_of_service
|
||||||
log_out
|
log_out
|
||||||
get_active_sessions
|
get_active_sessions
|
||||||
""",
|
""",
|
||||||
|
|
@ -465,7 +444,7 @@ def pyrogram_api():
|
||||||
fmt_keys = {}
|
fmt_keys = {}
|
||||||
|
|
||||||
for k, v in categories.items():
|
for k, v in categories.items():
|
||||||
_, *methods = get_title_list(v)
|
name, *methods = get_title_list(v)
|
||||||
fmt_keys.update({k: "\n ".join("{0} <{0}>".format(m) for m in methods)})
|
fmt_keys.update({k: "\n ".join("{0} <{0}>".format(m) for m in methods)})
|
||||||
|
|
||||||
for method in methods:
|
for method in methods:
|
||||||
|
|
@ -499,7 +478,6 @@ def pyrogram_api():
|
||||||
BusinessWeeklyOpen
|
BusinessWeeklyOpen
|
||||||
BusinessWorkingHours
|
BusinessWorkingHours
|
||||||
User
|
User
|
||||||
Username
|
|
||||||
Chat
|
Chat
|
||||||
ChatPreview
|
ChatPreview
|
||||||
ChatPhoto
|
ChatPhoto
|
||||||
|
|
@ -518,12 +496,10 @@ def pyrogram_api():
|
||||||
Folder
|
Folder
|
||||||
Restriction
|
Restriction
|
||||||
EmojiStatus
|
EmojiStatus
|
||||||
ExportedFolderLink
|
|
||||||
ForumTopic
|
ForumTopic
|
||||||
PeerUser
|
PeerUser
|
||||||
PeerChannel
|
PeerChannel
|
||||||
BotInfo
|
BotInfo
|
||||||
GroupCallMember
|
|
||||||
ChatColor
|
ChatColor
|
||||||
CollectibleItemInfo
|
CollectibleItemInfo
|
||||||
BotVerification
|
BotVerification
|
||||||
|
|
@ -532,23 +508,11 @@ def pyrogram_api():
|
||||||
Messages & Media
|
Messages & Media
|
||||||
Message
|
Message
|
||||||
MessageEntity
|
MessageEntity
|
||||||
MessageOriginChannel
|
|
||||||
MessageOriginChat
|
|
||||||
MessageOriginHiddenUser
|
|
||||||
MessageOriginImport
|
|
||||||
MessageOriginUser
|
|
||||||
MessageOrigin
|
|
||||||
Photo
|
Photo
|
||||||
Thumbnail
|
Thumbnail
|
||||||
TodoList
|
|
||||||
TodoTask
|
|
||||||
TodoTasksAdded
|
|
||||||
TodoTasksCompleted
|
|
||||||
TodoTasksIncompleted
|
|
||||||
Audio
|
Audio
|
||||||
AvailableEffect
|
AvailableEffect
|
||||||
Document
|
Document
|
||||||
ExternalReplyInfo
|
|
||||||
AlternativeVideo
|
AlternativeVideo
|
||||||
Animation
|
Animation
|
||||||
Video
|
Video
|
||||||
|
|
@ -569,9 +533,7 @@ def pyrogram_api():
|
||||||
WebPage
|
WebPage
|
||||||
WebPageEmpty
|
WebPageEmpty
|
||||||
WebPagePreview
|
WebPagePreview
|
||||||
TranscribedAudio
|
|
||||||
TranslatedText
|
TranslatedText
|
||||||
TextQuote
|
|
||||||
Poll
|
Poll
|
||||||
PollOption
|
PollOption
|
||||||
Dice
|
Dice
|
||||||
|
|
@ -587,7 +549,6 @@ def pyrogram_api():
|
||||||
ForumTopicCreated
|
ForumTopicCreated
|
||||||
ForumTopicEdited
|
ForumTopicEdited
|
||||||
ForumTopicClosed
|
ForumTopicClosed
|
||||||
ForumTopicDeleted
|
|
||||||
ForumTopicReopened
|
ForumTopicReopened
|
||||||
GeneralTopicHidden
|
GeneralTopicHidden
|
||||||
GeneralTopicUnhidden
|
GeneralTopicUnhidden
|
||||||
|
|
@ -627,7 +588,6 @@ def pyrogram_api():
|
||||||
Invoice
|
Invoice
|
||||||
LabeledPrice
|
LabeledPrice
|
||||||
PaidMedia
|
PaidMedia
|
||||||
PaidMessagePriceChanged
|
|
||||||
PaymentForm
|
PaymentForm
|
||||||
PaymentInfo
|
PaymentInfo
|
||||||
PaymentRefunded
|
PaymentRefunded
|
||||||
|
|
@ -737,20 +697,17 @@ def pyrogram_api():
|
||||||
InputMessageContent
|
InputMessageContent
|
||||||
InputMessageContent
|
InputMessageContent
|
||||||
InputReplyToMessage
|
InputReplyToMessage
|
||||||
InputReplyToMonoforum
|
|
||||||
InputReplyToStory
|
InputReplyToStory
|
||||||
InputTextMessageContent
|
InputTextMessageContent
|
||||||
InputLocationMessageContent
|
InputLocationMessageContent
|
||||||
InputVenueMessageContent
|
InputVenueMessageContent
|
||||||
InputContactMessageContent
|
InputContactMessageContent
|
||||||
InputInvoiceMessageContent
|
InputInvoiceMessageContent
|
||||||
InputTodoTask
|
|
||||||
""",
|
""",
|
||||||
authorization="""
|
authorization="""
|
||||||
Authorization
|
Authorization
|
||||||
ActiveSession
|
ActiveSession
|
||||||
ActiveSessions
|
ActiveSessions
|
||||||
LoginToken
|
|
||||||
SentCode
|
SentCode
|
||||||
TermsOfService
|
TermsOfService
|
||||||
"""
|
"""
|
||||||
|
|
@ -768,7 +725,7 @@ def pyrogram_api():
|
||||||
fmt_keys = {}
|
fmt_keys = {}
|
||||||
|
|
||||||
for k, v in categories.items():
|
for k, v in categories.items():
|
||||||
_, *types = get_title_list(v)
|
name, *types = get_title_list(v)
|
||||||
|
|
||||||
fmt_keys.update({k: "\n ".join(types)})
|
fmt_keys.update({k: "\n ".join(types)})
|
||||||
|
|
||||||
|
|
@ -822,7 +779,6 @@ def pyrogram_api():
|
||||||
Message.reply_web_page
|
Message.reply_web_page
|
||||||
Message.get_media_group
|
Message.get_media_group
|
||||||
Message.react
|
Message.react
|
||||||
Message.transcribe
|
|
||||||
Message.translate
|
Message.translate
|
||||||
Message.wait_for_click
|
Message.wait_for_click
|
||||||
""",
|
""",
|
||||||
|
|
@ -900,7 +856,6 @@ def pyrogram_api():
|
||||||
Gift.convert
|
Gift.convert
|
||||||
Gift.upgrade
|
Gift.upgrade
|
||||||
Gift.transfer
|
Gift.transfer
|
||||||
Gift.wear
|
|
||||||
""",
|
""",
|
||||||
callback_query="""
|
callback_query="""
|
||||||
Callback Query
|
Callback Query
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import ast
|
|
||||||
import csv
|
import csv
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
@ -38,13 +37,6 @@ def caml(s):
|
||||||
s = snek(s).split("_")
|
s = snek(s).split("_")
|
||||||
return "".join([str(i.title()) for i in s])
|
return "".join([str(i.title()) for i in s])
|
||||||
|
|
||||||
def get_classes_from_file(file_path):
|
|
||||||
with open(file_path, "r", encoding="utf-8") as f:
|
|
||||||
tree = ast.parse(f.read())
|
|
||||||
|
|
||||||
classes = [node.name for node in ast.walk(tree) if isinstance(node, ast.ClassDef)]
|
|
||||||
return classes
|
|
||||||
|
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
shutil.rmtree(DEST, ignore_errors=True)
|
shutil.rmtree(DEST, ignore_errors=True)
|
||||||
|
|
@ -135,20 +127,6 @@ def start():
|
||||||
f_all.write(" },\n")
|
f_all.write(" },\n")
|
||||||
|
|
||||||
f_all.write("}\n")
|
f_all.write("}\n")
|
||||||
with open(init, "a", encoding="utf-8") as f_init:
|
|
||||||
f_init.write("\n")
|
|
||||||
all_classes = []
|
|
||||||
for i in files:
|
|
||||||
code, name = re.search(r"(\d+)_([A-Z_]+)", i).groups()
|
|
||||||
classes = get_classes_from_file("{}/{}_{}.py".format(DEST, name.lower(), code))
|
|
||||||
for j in classes:
|
|
||||||
if j not in ["BaseException", "Exception", "PyrogramException"]:
|
|
||||||
all_classes.append(j)
|
|
||||||
f_init.write("__all__ = [\n")
|
|
||||||
all_classes = sorted(set(all_classes))
|
|
||||||
for i in all_classes:
|
|
||||||
f_init.write(" \"{}\",\n".format(i))
|
|
||||||
f_init.write("]\n")
|
|
||||||
|
|
||||||
with open("{}/all.py".format(DEST), encoding="utf-8") as f:
|
with open("{}/all.py".format(DEST), encoding="utf-8") as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ BOT_GAMES_DISABLED Bot games cannot be used in this type of chat
|
||||||
BOT_GROUPS_BLOCKED This bot can't be added to groups
|
BOT_GROUPS_BLOCKED This bot can't be added to groups
|
||||||
BOT_INLINE_DISABLED The inline feature of the bot is disabled
|
BOT_INLINE_DISABLED The inline feature of the bot is disabled
|
||||||
BOT_INVALID This is not a valid bot
|
BOT_INVALID This is not a valid bot
|
||||||
BOT_INVOICE_INVALID The provided invoice is invalid
|
|
||||||
BOT_METHOD_INVALID The method can't be used by bots
|
BOT_METHOD_INVALID The method can't be used by bots
|
||||||
BOT_MISSING This method can only be run by a bot
|
BOT_MISSING This method can only be run by a bot
|
||||||
BOT_ONESIDE_NOT_AVAIL Bots can't pin messages for one side only in private chats
|
BOT_ONESIDE_NOT_AVAIL Bots can't pin messages for one side only in private chats
|
||||||
|
|
@ -47,7 +46,6 @@ BROADCAST_CALLS_DISABLED Broadcast calls disabled
|
||||||
BROADCAST_ID_INVALID The channel is invalid
|
BROADCAST_ID_INVALID The channel is invalid
|
||||||
BROADCAST_PUBLIC_VOTERS_FORBIDDEN Polls with public voters cannot be sent in channels
|
BROADCAST_PUBLIC_VOTERS_FORBIDDEN Polls with public voters cannot be sent in channels
|
||||||
BROADCAST_REQUIRED The request can only be used with a channel
|
BROADCAST_REQUIRED The request can only be used with a channel
|
||||||
BUSINESS_BOT_MISSING Business bot missing
|
|
||||||
BUTTON_DATA_INVALID The button callback data is invalid or too large
|
BUTTON_DATA_INVALID The button callback data is invalid or too large
|
||||||
BUTTON_ID_INVALID The button_id parameter is invalid
|
BUTTON_ID_INVALID The button_id parameter is invalid
|
||||||
BUTTON_TEXT_INVALID The specified button text is invalid
|
BUTTON_TEXT_INVALID The specified button text is invalid
|
||||||
|
|
@ -505,4 +503,3 @@ BOOSTS_EMPTY You can't modify the icon of the General topic.
|
||||||
BOOST_NOT_MODIFIED You're already boosting the specified channel.
|
BOOST_NOT_MODIFIED You're already boosting the specified channel.
|
||||||
PAYMENT_REQUIRED The payment is required
|
PAYMENT_REQUIRED The payment is required
|
||||||
BOOST_PEER_INVALID The specified `boost_peer` is invalid.
|
BOOST_PEER_INVALID The specified `boost_peer` is invalid.
|
||||||
STARS_AMOUNT_INVALID The specified `amount` is invalid.
|
|
||||||
|
|
|
@ -44,4 +44,3 @@ GROUPCALL_ALREADY_STARTED The groupcall has already started, you can join direct
|
||||||
GROUPCALL_FORBIDDEN The group call has already ended
|
GROUPCALL_FORBIDDEN The group call has already ended
|
||||||
LIVE_DISABLED Story is disabled server-side
|
LIVE_DISABLED Story is disabled server-side
|
||||||
CHAT_GUEST_SEND_FORBIDDEN You need to join the discussion group before commenting
|
CHAT_GUEST_SEND_FORBIDDEN You need to join the discussion group before commenting
|
||||||
ALLOW_PAYMENT_REQUIRED_X Payment of {value} stars is required to perform this action
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
GiftAttributeType
|
|
||||||
=================
|
|
||||||
|
|
||||||
.. autoclass:: pyrogram.enums.GiftForResaleOrder()
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. raw:: html
|
|
||||||
:file: ./cleanup.html
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
MessageOriginType
|
|
||||||
=================
|
|
||||||
|
|
||||||
.. autoclass:: pyrogram.enums.MessageOriginType()
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. raw:: html
|
|
||||||
:file: ./cleanup.html
|
|
||||||
|
|
@ -29,7 +29,7 @@ from pygments.styles.friendly import FriendlyStyle
|
||||||
FriendlyStyle.background_color = "#f3f2f1"
|
FriendlyStyle.background_color = "#f3f2f1"
|
||||||
|
|
||||||
project = "Pyrofork"
|
project = "Pyrofork"
|
||||||
copyright = "2022-present, Mayuri-Chan"
|
copyright = f"2022-present, Mayuri-Chan"
|
||||||
author = "Mayuri-Chan"
|
author = "Mayuri-Chan"
|
||||||
|
|
||||||
version = ".".join(__version__.split(".")[:-1])
|
version = ".".join(__version__.split(".")[:-1])
|
||||||
|
|
@ -73,7 +73,7 @@ html_theme_options = {
|
||||||
"repo": "fontawesome/brands/github",
|
"repo": "fontawesome/brands/github",
|
||||||
"edit": "material/file-edit-outline",
|
"edit": "material/file-edit-outline",
|
||||||
},
|
},
|
||||||
"site_url": "https://pyrofork.wulan17.dev/",
|
"site_url": "https://pyrofork.wulan17.top/",
|
||||||
"repo_url": "https://github.com/Mayuri-Chan/pyrofork/",
|
"repo_url": "https://github.com/Mayuri-Chan/pyrofork/",
|
||||||
"repo_name": "pyrofork",
|
"repo_name": "pyrofork",
|
||||||
"globaltoc_collapse": True,
|
"globaltoc_collapse": True,
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ like send_audio(), send_document(), send_location(), etc...
|
||||||
),
|
),
|
||||||
InlineKeyboardButton( # Opens a web URL
|
InlineKeyboardButton( # Opens a web URL
|
||||||
"URL",
|
"URL",
|
||||||
url="https://pyrofork.wulan17.dev"
|
url="https://pyrofork.wulan17.top"
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
[ # Second row
|
[ # Second row
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,13 @@ It uses the @on_inline_query decorator to register an InlineQueryHandler.
|
||||||
input_message_content=InputTextMessageContent(
|
input_message_content=InputTextMessageContent(
|
||||||
"Here's how to install **Pyrofork**"
|
"Here's how to install **Pyrofork**"
|
||||||
),
|
),
|
||||||
url="https://pyrofork.wulan17.dev/intro/install",
|
url="https://pyrofork.wulan17.top/intro/install",
|
||||||
description="How to install Pyrofork",
|
description="How to install Pyrofork",
|
||||||
reply_markup=InlineKeyboardMarkup(
|
reply_markup=InlineKeyboardMarkup(
|
||||||
[
|
[
|
||||||
[InlineKeyboardButton(
|
[InlineKeyboardButton(
|
||||||
"Open website",
|
"Open website",
|
||||||
url="https://pyrofork.wulan17.dev/intro/install"
|
url="https://pyrofork.wulan17.top/intro/install"
|
||||||
)]
|
)]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
@ -40,13 +40,13 @@ It uses the @on_inline_query decorator to register an InlineQueryHandler.
|
||||||
input_message_content=InputTextMessageContent(
|
input_message_content=InputTextMessageContent(
|
||||||
"Here's how to use **Pyrofork**"
|
"Here's how to use **Pyrofork**"
|
||||||
),
|
),
|
||||||
url="https://pyrofork.wulan17.dev/start/invoking",
|
url="https://pyrofork.wulan17.top/start/invoking",
|
||||||
description="How to use Pyrofork",
|
description="How to use Pyrofork",
|
||||||
reply_markup=InlineKeyboardMarkup(
|
reply_markup=InlineKeyboardMarkup(
|
||||||
[
|
[
|
||||||
[InlineKeyboardButton(
|
[InlineKeyboardButton(
|
||||||
"Open website",
|
"Open website",
|
||||||
url="https://pyrofork.wulan17.dev/start/invoking"
|
url="https://pyrofork.wulan17.top/start/invoking"
|
||||||
)]
|
)]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ to make it only work for specific messages in a specific chat.
|
||||||
# Target chat. Can also be a list of multiple chat ids/usernames
|
# Target chat. Can also be a list of multiple chat ids/usernames
|
||||||
TARGET = -100123456789
|
TARGET = -100123456789
|
||||||
# Welcome message template
|
# Welcome message template
|
||||||
MESSAGE = "{} Welcome to [Pyrofork](https://pyrofork.wulan17.dev/)'s group chat {}!"
|
MESSAGE = "{} Welcome to [Pyrofork](https://pyrofork.wulan17.top/)'s group chat {}!"
|
||||||
|
|
||||||
app = Client("my_account")
|
app = Client("my_account")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,20 +80,7 @@ Using async_pymongo (Recommended for python3.9+):
|
||||||
print(await app.get_me())
|
print(await app.get_me())
|
||||||
|
|
||||||
|
|
||||||
Using official mongodb driver:
|
Using motor:
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from pymongo import AsyncMongoClient
|
|
||||||
from pyrogram import Client
|
|
||||||
|
|
||||||
conn = AsyncMongoClient("mongodb://...")
|
|
||||||
|
|
||||||
async with Client("my_account", mongodb=dict(connection=conn, remove_peers=False)) as app:
|
|
||||||
print(await app.get_me())
|
|
||||||
|
|
||||||
|
|
||||||
Using motor (Deprecated, but still works):
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,16 +37,68 @@ list of the basic styles currently supported by Pyrofork.
|
||||||
- spoiler
|
- spoiler
|
||||||
- `text URL <https://pyrogram.org>`_
|
- `text URL <https://pyrogram.org>`_
|
||||||
- `user text mention <tg://user?id=123456789>`_
|
- `user text mention <tg://user?id=123456789>`_
|
||||||
- :emoji:`🔥`
|
|
||||||
- ``inline fixed-width code``
|
- ``inline fixed-width code``
|
||||||
- .. code-block:: text
|
- .. code-block:: text
|
||||||
|
|
||||||
pre-formatted
|
pre-formatted
|
||||||
fixed-width
|
fixed-width
|
||||||
code block
|
code block
|
||||||
- > Quoted text
|
|
||||||
|
|
||||||
- > Quoted text with collapse/expand button
|
Markdown Style
|
||||||
|
--------------
|
||||||
|
|
||||||
|
To strictly use this mode, pass :obj:`~pyrogram.enums.ParseMode.MARKDOWN` to the *parse_mode* parameter when using
|
||||||
|
:meth:`~pyrogram.Client.send_message`. Use the following syntax in your message:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
**bold**
|
||||||
|
|
||||||
|
__italic__
|
||||||
|
|
||||||
|
--underline--
|
||||||
|
|
||||||
|
~~strike~~
|
||||||
|
|
||||||
|
||spoiler||
|
||||||
|
|
||||||
|
[text URL](https://pyrogram.org/)
|
||||||
|
|
||||||
|
[text user mention](tg://user?id=123456789)
|
||||||
|
|
||||||
|
`inline fixed-width code`
|
||||||
|
|
||||||
|
```
|
||||||
|
pre-formatted
|
||||||
|
fixed-width
|
||||||
|
code block
|
||||||
|
```
|
||||||
|
|
||||||
|
> Quoted text
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from pyrogram import enums
|
||||||
|
|
||||||
|
await app.send_message(
|
||||||
|
"me",
|
||||||
|
(
|
||||||
|
"**bold**, "
|
||||||
|
"__italic__, "
|
||||||
|
"--underline--, "
|
||||||
|
"~~strike~~, "
|
||||||
|
"||spoiler||, "
|
||||||
|
"[URL](https://pyrogram.org), "
|
||||||
|
"`code`, "
|
||||||
|
"```"
|
||||||
|
"for i in range(10):\n"
|
||||||
|
" print(i)"
|
||||||
|
"```"
|
||||||
|
),
|
||||||
|
parse_mode=enums.ParseMode.MARKDOWN
|
||||||
|
)
|
||||||
|
|
||||||
HTML Style
|
HTML Style
|
||||||
----------
|
----------
|
||||||
|
|
@ -70,10 +122,10 @@ To strictly use this mode, pass :obj:`~pyrogram.enums.HTML` to the *parse_mode*
|
||||||
|
|
||||||
<a href="tg://user?id=123456789">inline mention</a>
|
<a href="tg://user?id=123456789">inline mention</a>
|
||||||
|
|
||||||
<emoji id="12345678901234567890">🔥</emoji>
|
|
||||||
|
|
||||||
<code>inline fixed-width code</code>
|
<code>inline fixed-width code</code>
|
||||||
|
|
||||||
|
<emoji id="12345678901234567890">🔥</emoji>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
pre-formatted
|
pre-formatted
|
||||||
fixed-width
|
fixed-width
|
||||||
|
|
@ -82,8 +134,6 @@ To strictly use this mode, pass :obj:`~pyrogram.enums.HTML` to the *parse_mode*
|
||||||
|
|
||||||
<blockquote>Quoted text</blockquote>
|
<blockquote>Quoted text</blockquote>
|
||||||
|
|
||||||
<blockquote expandable>Quoted text with collapse/expand button</blockquote>
|
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
@ -128,72 +178,6 @@ To strictly use this mode, pass :obj:`~pyrogram.enums.HTML` to the *parse_mode*
|
||||||
|
|
||||||
<my text>
|
<my text>
|
||||||
|
|
||||||
Markdown Style
|
|
||||||
--------------
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
The Markdown style is not recommended for complex text formatting.
|
|
||||||
If you want to use complex text formatting such as nested entities, overlapping entities use the HTML style instead.
|
|
||||||
|
|
||||||
|
|
||||||
To strictly use this mode, pass :obj:`~pyrogram.enums.ParseMode.MARKDOWN` to the *parse_mode* parameter when using
|
|
||||||
:meth:`~pyrogram.Client.send_message`. Use the following syntax in your message:
|
|
||||||
|
|
||||||
.. code-block:: text
|
|
||||||
|
|
||||||
**bold**
|
|
||||||
|
|
||||||
__italic__
|
|
||||||
|
|
||||||
--underline--
|
|
||||||
|
|
||||||
~~strike~~
|
|
||||||
|
|
||||||
||spoiler||
|
|
||||||
|
|
||||||
[text URL](https://pyrogram.org/)
|
|
||||||
|
|
||||||
[text user mention](tg://user?id=123456789)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
`inline fixed-width code`
|
|
||||||
|
|
||||||
```
|
|
||||||
pre-formatted
|
|
||||||
fixed-width
|
|
||||||
code block
|
|
||||||
```
|
|
||||||
|
|
||||||
> Quoted text
|
|
||||||
|
|
||||||
**> Quoted text with collapse/expand button
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from pyrogram import enums
|
|
||||||
|
|
||||||
await app.send_message(
|
|
||||||
"me",
|
|
||||||
(
|
|
||||||
"**bold**, "
|
|
||||||
"__italic__, "
|
|
||||||
"--underline--, "
|
|
||||||
"~~strike~~, "
|
|
||||||
"||spoiler||, "
|
|
||||||
"[URL](https://pyrogram.org), "
|
|
||||||
"`code`, "
|
|
||||||
"```"
|
|
||||||
"for i in range(10):\n"
|
|
||||||
" print(i)"
|
|
||||||
"```"
|
|
||||||
),
|
|
||||||
parse_mode=enums.ParseMode.MARKDOWN
|
|
||||||
)
|
|
||||||
|
|
||||||
Different Styles
|
Different Styles
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
@ -246,18 +230,18 @@ strike` styles, and you can still combine both Markdown and HTML together.
|
||||||
|
|
||||||
Here there are some example texts you can try sending:
|
Here there are some example texts you can try sending:
|
||||||
|
|
||||||
|
**Markdown**:
|
||||||
|
|
||||||
|
- ``**bold, --underline--**``
|
||||||
|
- ``**bold __italic --underline ~~strike~~--__**``
|
||||||
|
- ``**bold __and** italic__``
|
||||||
|
|
||||||
**HTML**:
|
**HTML**:
|
||||||
|
|
||||||
- ``<b>bold, <u>underline</u></b>``
|
- ``<b>bold, <u>underline</u></b>``
|
||||||
- ``<b>bold <i>italic <u>underline <s>strike</s></u></i></b>``
|
- ``<b>bold <i>italic <u>underline <s>strike</s></u></i></b>``
|
||||||
- ``<b>bold <i>and</b> italic</i>``
|
- ``<b>bold <i>and</b> italic</i>``
|
||||||
|
|
||||||
**Markdown (Not Recommended)**:
|
|
||||||
|
|
||||||
- ``**bold, --underline--**``
|
|
||||||
- ``**bold __italic --underline ~~strike~~--__**``
|
|
||||||
- ``**bold __and** italic__``
|
|
||||||
|
|
||||||
**Combined**:
|
**Combined**:
|
||||||
|
|
||||||
- ``--you can combine <i>HTML</i> with **Markdown**--``
|
- ``--you can combine <i>HTML</i> with **Markdown**--``
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ authors = [{ name = "wulan17", email = "mayuri@mayuri.my.id" }]
|
||||||
dependencies = ["pyaes==1.6.1", "pysocks==1.7.1", "pymediainfo-pyrofork>=6.0.1,<7.0.0"]
|
dependencies = ["pyaes==1.6.1", "pysocks==1.7.1", "pymediainfo-pyrofork>=6.0.1,<7.0.0"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = "LGPL-3.0-or-later"
|
license = "LGPL-3.0-or-later"
|
||||||
requires-python = "~=3.10"
|
requires-python = "~=3.9"
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Development Status :: 5 - Production/Stable",
|
"Development Status :: 5 - Production/Stable",
|
||||||
"Intended Audience :: Developers",
|
"Intended Audience :: Developers",
|
||||||
|
|
@ -15,11 +15,11 @@ classifiers = [
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
"Programming Language :: Python :: 3.13",
|
"Programming Language :: Python :: 3.13",
|
||||||
"Programming Language :: Python :: 3.14",
|
|
||||||
"Programming Language :: Python :: Implementation",
|
"Programming Language :: Python :: Implementation",
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
"Programming Language :: Python :: Implementation :: PyPy",
|
||||||
|
|
@ -43,7 +43,7 @@ Homepage = "https://github.com/Mayuri-Chan"
|
||||||
Tracker = "https://github.com/Mayuri-Chan/pyrofork/issues"
|
Tracker = "https://github.com/Mayuri-Chan/pyrofork/issues"
|
||||||
Community = "https://t.me/MayuriChan_Chat"
|
Community = "https://t.me/MayuriChan_Chat"
|
||||||
Source = "https://github.com/Mayuri-Chan/pyrofork"
|
Source = "https://github.com/Mayuri-Chan/pyrofork"
|
||||||
Documentation = "https://pyrofork.wulan17.dev"
|
Documentation = "https://pyrofork.wulan17.top"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling"]
|
||||||
|
|
@ -60,7 +60,7 @@ dev = [
|
||||||
|
|
||||||
docs = [
|
docs = [
|
||||||
"sphinx",
|
"sphinx",
|
||||||
"sphinx-immaterial==0.12.5",
|
"sphinx-immaterial==0.12.4",
|
||||||
"sphinx_copybutton",
|
"sphinx_copybutton",
|
||||||
"sphinx-autobuild",
|
"sphinx-autobuild",
|
||||||
"tornado>=6.3.3"
|
"tornado>=6.3.3"
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
__fork_name__ = "PyroFork"
|
__fork_name__ = "PyroFork"
|
||||||
__version__ = "2.3.69"
|
__version__ = "2.3.55"
|
||||||
__license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)"
|
__license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)"
|
||||||
__copyright__ = "Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>"
|
__copyright__ = "Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>"
|
||||||
|
|
||||||
|
|
@ -37,24 +37,8 @@ class ContinuePropagation(StopAsyncIteration):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
from . import raw, types, filters, handlers, emoji, enums # pylint: disable=wrong-import-position
|
from . import raw, types, filters, handlers, emoji, enums
|
||||||
from .client import Client # pylint: disable=wrong-import-position
|
from .client import Client
|
||||||
from .sync import idle, compose # pylint: disable=wrong-import-position
|
from .sync import idle, compose
|
||||||
|
|
||||||
crypto_executor = ThreadPoolExecutor(1, thread_name_prefix="CryptoWorker")
|
crypto_executor = ThreadPoolExecutor(1, thread_name_prefix="CryptoWorker")
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
"Client",
|
|
||||||
"idle",
|
|
||||||
"compose",
|
|
||||||
"crypto_executor",
|
|
||||||
"StopTransmission",
|
|
||||||
"StopPropagation",
|
|
||||||
"ContinuePropagation",
|
|
||||||
"raw",
|
|
||||||
"types",
|
|
||||||
"filters",
|
|
||||||
"handlers",
|
|
||||||
"emoji",
|
|
||||||
"enums",
|
|
||||||
]
|
|
||||||
|
|
|
||||||
|
|
@ -33,13 +33,12 @@ from importlib import import_module
|
||||||
from io import StringIO, BytesIO
|
from io import StringIO, BytesIO
|
||||||
from mimetypes import MimeTypes
|
from mimetypes import MimeTypes
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Union, List, Optional, Callable, AsyncGenerator, Tuple
|
from typing import Union, List, Optional, Callable, AsyncGenerator, Type, Tuple
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import __version__, __license__
|
from pyrogram import __version__, __license__
|
||||||
from pyrogram import enums
|
from pyrogram import enums
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
from pyrogram import types
|
|
||||||
from pyrogram import utils
|
from pyrogram import utils
|
||||||
from pyrogram.crypto import aes
|
from pyrogram.crypto import aes
|
||||||
from pyrogram.errors import CDNFileHashMismatch
|
from pyrogram.errors import CDNFileHashMismatch
|
||||||
|
|
@ -52,26 +51,24 @@ from pyrogram.handlers.handler import Handler
|
||||||
from pyrogram.methods import Methods
|
from pyrogram.methods import Methods
|
||||||
from pyrogram.session import Auth, Session
|
from pyrogram.session import Auth, Session
|
||||||
from pyrogram.storage import FileStorage, MemoryStorage, Storage
|
from pyrogram.storage import FileStorage, MemoryStorage, Storage
|
||||||
from pyrogram.types import User
|
|
||||||
from pyrogram.utils import ainput
|
|
||||||
from .connection import Connection
|
|
||||||
from .connection.transport import TCPAbridged
|
|
||||||
from .dispatcher import Dispatcher
|
|
||||||
from .file_id import FileId, FileType, ThumbnailSource
|
|
||||||
from .mime_types import mime_types
|
|
||||||
from .parser import Parser
|
|
||||||
from .session.internals import MsgId
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
MONGO_AVAIL = False
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import pymongo
|
import pymongo
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
from pyrogram.storage import MongoStorage
|
from pyrogram.storage import MongoStorage
|
||||||
MONGO_AVAIL = True
|
from pyrogram.types import User, TermsOfService
|
||||||
|
from pyrogram.utils import ainput
|
||||||
|
from .connection import Connection
|
||||||
|
from .connection.transport import TCP, TCPAbridged
|
||||||
|
from .dispatcher import Dispatcher
|
||||||
|
from .file_id import FileId, FileType, ThumbnailSource
|
||||||
|
from .filters import Filter
|
||||||
|
from .mime_types import mime_types
|
||||||
|
from .parser import Parser
|
||||||
|
from .session.internals import MsgId
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Client(Methods):
|
class Client(Methods):
|
||||||
|
|
@ -131,9 +128,6 @@ class Client(Methods):
|
||||||
Pass a session string to load the session in-memory.
|
Pass a session string to load the session in-memory.
|
||||||
Implies ``in_memory=True``.
|
Implies ``in_memory=True``.
|
||||||
|
|
||||||
use_qrcode (``bool``, *optional*):
|
|
||||||
Pass True to login using a QR code.
|
|
||||||
|
|
||||||
in_memory (``bool``, *optional*):
|
in_memory (``bool``, *optional*):
|
||||||
Pass True to start an in-memory session that will be discarded as soon as the client stops.
|
Pass True to start an in-memory session that will be discarded as soon as the client stops.
|
||||||
In order to reconnect again using an in-memory session without having to login again, you can use
|
In order to reconnect again using an in-memory session without having to login again, you can use
|
||||||
|
|
@ -227,13 +221,10 @@ class Client(Methods):
|
||||||
SYSTEM_VERSION = f"{platform.system()} {platform.release()}"
|
SYSTEM_VERSION = f"{platform.system()} {platform.release()}"
|
||||||
|
|
||||||
LANG_CODE = "en"
|
LANG_CODE = "en"
|
||||||
LANG_PACK = ""
|
|
||||||
SYSTEM_LANG_CODE = "en-US"
|
|
||||||
|
|
||||||
PARENT_DIR = Path(sys.argv[0]).parent
|
PARENT_DIR = Path(sys.argv[0]).parent
|
||||||
|
|
||||||
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/(?:joinchat/|\+))([\w-]+)$")
|
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/(?:joinchat/|\+))([\w-]+)$")
|
||||||
UPGRADED_GIFT_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/(?:nft/|\+))([\w-]+)$")
|
|
||||||
WORKERS = min(32, (os.cpu_count() or 0) + 4) # os.cpu_count() can be None
|
WORKERS = min(32, (os.cpu_count() or 0) + 4) # os.cpu_count() can be None
|
||||||
WORKDIR = PARENT_DIR
|
WORKDIR = PARENT_DIR
|
||||||
|
|
||||||
|
|
@ -254,16 +245,13 @@ class Client(Methods):
|
||||||
app_version: str = APP_VERSION,
|
app_version: str = APP_VERSION,
|
||||||
device_model: str = DEVICE_MODEL,
|
device_model: str = DEVICE_MODEL,
|
||||||
system_version: str = SYSTEM_VERSION,
|
system_version: str = SYSTEM_VERSION,
|
||||||
system_lang_code: str = SYSTEM_LANG_CODE,
|
|
||||||
lang_code: str = LANG_CODE,
|
lang_code: str = LANG_CODE,
|
||||||
lang_pack: str = LANG_PACK,
|
|
||||||
ipv6: Optional[bool] = False,
|
ipv6: Optional[bool] = False,
|
||||||
alt_port: Optional[bool] = False,
|
alt_port: Optional[bool] = False,
|
||||||
proxy: Optional[dict] = None,
|
proxy: Optional[dict] = None,
|
||||||
test_mode: Optional[bool] = False,
|
test_mode: Optional[bool] = False,
|
||||||
bot_token: Optional[str] = None,
|
bot_token: Optional[str] = None,
|
||||||
session_string: Optional[str] = None,
|
session_string: Optional[str] = None,
|
||||||
use_qrcode: Optional[bool] = False,
|
|
||||||
in_memory: Optional[bool] = None,
|
in_memory: Optional[bool] = None,
|
||||||
mongodb: Optional[dict] = None,
|
mongodb: Optional[dict] = None,
|
||||||
storage: Optional[Storage] = None,
|
storage: Optional[Storage] = None,
|
||||||
|
|
@ -278,7 +266,7 @@ class Client(Methods):
|
||||||
skip_updates: bool = True,
|
skip_updates: bool = True,
|
||||||
takeout: bool = None,
|
takeout: bool = None,
|
||||||
sleep_threshold: int = Session.SLEEP_THRESHOLD,
|
sleep_threshold: int = Session.SLEEP_THRESHOLD,
|
||||||
hide_password: Optional[bool] = True,
|
hide_password: Optional[bool] = False,
|
||||||
max_concurrent_transmissions: int = MAX_CONCURRENT_TRANSMISSIONS,
|
max_concurrent_transmissions: int = MAX_CONCURRENT_TRANSMISSIONS,
|
||||||
client_platform: "enums.ClientPlatform" = enums.ClientPlatform.OTHER,
|
client_platform: "enums.ClientPlatform" = enums.ClientPlatform.OTHER,
|
||||||
max_message_cache_size: int = MAX_CACHE_SIZE,
|
max_message_cache_size: int = MAX_CACHE_SIZE,
|
||||||
|
|
@ -292,16 +280,13 @@ class Client(Methods):
|
||||||
self.app_version = app_version
|
self.app_version = app_version
|
||||||
self.device_model = device_model
|
self.device_model = device_model
|
||||||
self.system_version = system_version
|
self.system_version = system_version
|
||||||
self.system_lang_code = system_lang_code.lower()
|
|
||||||
self.lang_code = lang_code.lower()
|
self.lang_code = lang_code.lower()
|
||||||
self.lang_pack = lang_pack.lower()
|
|
||||||
self.ipv6 = ipv6
|
self.ipv6 = ipv6
|
||||||
self.alt_port = alt_port
|
self.alt_port = alt_port
|
||||||
self.proxy = proxy
|
self.proxy = proxy
|
||||||
self.test_mode = test_mode
|
self.test_mode = test_mode
|
||||||
self.bot_token = bot_token
|
self.bot_token = bot_token
|
||||||
self.session_string = session_string
|
self.session_string = session_string
|
||||||
self.use_qrcode = use_qrcode
|
|
||||||
self.in_memory = in_memory
|
self.in_memory = in_memory
|
||||||
self.mongodb = mongodb
|
self.mongodb = mongodb
|
||||||
self.phone_number = phone_number
|
self.phone_number = phone_number
|
||||||
|
|
@ -331,7 +316,9 @@ class Client(Methods):
|
||||||
elif self.in_memory:
|
elif self.in_memory:
|
||||||
self.storage = MemoryStorage(self.name)
|
self.storage = MemoryStorage(self.name)
|
||||||
elif self.mongodb:
|
elif self.mongodb:
|
||||||
if not MONGO_AVAIL:
|
try:
|
||||||
|
import pymongo
|
||||||
|
except Exception:
|
||||||
log.warning(
|
log.warning(
|
||||||
"pymongo is missing! "
|
"pymongo is missing! "
|
||||||
"Using MemoryStorage as session storage"
|
"Using MemoryStorage as session storage"
|
||||||
|
|
@ -410,15 +397,6 @@ class Client(Methods):
|
||||||
if datetime.now() - self.last_update_time > timedelta(seconds=self.UPDATES_WATCHDOG_INTERVAL):
|
if datetime.now() - self.last_update_time > timedelta(seconds=self.UPDATES_WATCHDOG_INTERVAL):
|
||||||
await self.invoke(raw.functions.updates.GetState())
|
await self.invoke(raw.functions.updates.GetState())
|
||||||
|
|
||||||
async def _wait_for_update_login_token(self):
|
|
||||||
"""
|
|
||||||
Wait for an UpdateLoginToken update from Telegram.
|
|
||||||
"""
|
|
||||||
while True:
|
|
||||||
update, _, _ = await self.dispatcher.updates_queue.get()
|
|
||||||
if isinstance(update, raw.types.UpdateLoginToken):
|
|
||||||
break
|
|
||||||
|
|
||||||
async def authorize(self) -> User:
|
async def authorize(self) -> User:
|
||||||
if self.bot_token:
|
if self.bot_token:
|
||||||
return await self.sign_in_bot(self.bot_token)
|
return await self.sign_in_bot(self.bot_token)
|
||||||
|
|
@ -426,60 +404,52 @@ class Client(Methods):
|
||||||
print(f"Welcome to Pyrogram (version {__version__})")
|
print(f"Welcome to Pyrogram (version {__version__})")
|
||||||
print(f"Pyrogram is free software and comes with ABSOLUTELY NO WARRANTY. Licensed\n"
|
print(f"Pyrogram is free software and comes with ABSOLUTELY NO WARRANTY. Licensed\n"
|
||||||
f"under the terms of the {__license__}.\n")
|
f"under the terms of the {__license__}.\n")
|
||||||
if not self.use_qrcode:
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
if not self.phone_number:
|
|
||||||
while True:
|
|
||||||
print("Enter 'qrcode' if you want to login with qrcode.")
|
|
||||||
value = await ainput("Enter phone number or bot token: ")
|
|
||||||
|
|
||||||
if not value:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if value.lower() == "qrcode":
|
|
||||||
self.use_qrcode = True
|
|
||||||
break
|
|
||||||
|
|
||||||
confirm = (await ainput(f'Is "{value}" correct? (y/N): ')).lower()
|
|
||||||
|
|
||||||
if confirm == "y":
|
|
||||||
break
|
|
||||||
|
|
||||||
if ":" in value:
|
|
||||||
self.bot_token = value
|
|
||||||
return await self.sign_in_bot(value)
|
|
||||||
else:
|
|
||||||
self.phone_number = value
|
|
||||||
if not self.use_qrcode:
|
|
||||||
sent_code = await self.send_code(self.phone_number)
|
|
||||||
except BadRequest as e:
|
|
||||||
print(e.MESSAGE)
|
|
||||||
self.phone_number = None
|
|
||||||
self.bot_token = None
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
if not self.use_qrcode:
|
|
||||||
sent_code_descriptions = {
|
|
||||||
enums.SentCodeType.APP: "Telegram app",
|
|
||||||
enums.SentCodeType.SMS: "SMS",
|
|
||||||
enums.SentCodeType.CALL: "phone call",
|
|
||||||
enums.SentCodeType.FLASH_CALL: "phone flash call",
|
|
||||||
enums.SentCodeType.FRAGMENT_SMS: "Fragment SMS",
|
|
||||||
enums.SentCodeType.EMAIL_CODE: "email code"
|
|
||||||
}
|
|
||||||
|
|
||||||
print(f"The confirmation code has been sent via {sent_code_descriptions[sent_code.type]}")
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if not self.use_qrcode and not self.phone_code:
|
try:
|
||||||
|
if not self.phone_number:
|
||||||
|
while True:
|
||||||
|
value = await ainput("Enter phone number or bot token: ")
|
||||||
|
|
||||||
|
if not value:
|
||||||
|
continue
|
||||||
|
|
||||||
|
confirm = (await ainput(f'Is "{value}" correct? (y/N): ')).lower()
|
||||||
|
|
||||||
|
if confirm == "y":
|
||||||
|
break
|
||||||
|
|
||||||
|
if ":" in value:
|
||||||
|
self.bot_token = value
|
||||||
|
return await self.sign_in_bot(value)
|
||||||
|
else:
|
||||||
|
self.phone_number = value
|
||||||
|
|
||||||
|
sent_code = await self.send_code(self.phone_number)
|
||||||
|
except BadRequest as e:
|
||||||
|
print(e.MESSAGE)
|
||||||
|
self.phone_number = None
|
||||||
|
self.bot_token = None
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
sent_code_descriptions = {
|
||||||
|
enums.SentCodeType.APP: "Telegram app",
|
||||||
|
enums.SentCodeType.SMS: "SMS",
|
||||||
|
enums.SentCodeType.CALL: "phone call",
|
||||||
|
enums.SentCodeType.FLASH_CALL: "phone flash call",
|
||||||
|
enums.SentCodeType.FRAGMENT_SMS: "Fragment SMS",
|
||||||
|
enums.SentCodeType.EMAIL_CODE: "email code"
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"The confirmation code has been sent via {sent_code_descriptions[sent_code.type]}")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if not self.phone_code:
|
||||||
self.phone_code = await ainput("Enter confirmation code: ")
|
self.phone_code = await ainput("Enter confirmation code: ")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.use_qrcode:
|
signed_in = await self.sign_in(self.phone_number, sent_code.phone_code_hash, self.phone_code)
|
||||||
signed_in = await self.sign_in_qrcode()
|
|
||||||
else:
|
|
||||||
signed_in = await self.sign_in(self.phone_number, sent_code.phone_code_hash, self.phone_code)
|
|
||||||
except BadRequest as e:
|
except BadRequest as e:
|
||||||
print(e.MESSAGE)
|
print(e.MESSAGE)
|
||||||
self.phone_code = None
|
self.phone_code = None
|
||||||
|
|
@ -518,18 +488,33 @@ class Client(Methods):
|
||||||
print(e.MESSAGE)
|
print(e.MESSAGE)
|
||||||
self.password = None
|
self.password = None
|
||||||
else:
|
else:
|
||||||
if self.use_qrcode and isinstance(signed_in, types.LoginToken):
|
|
||||||
time_out = signed_in.expires - datetime.timestamp(datetime.now())
|
|
||||||
try:
|
|
||||||
await asyncio.wait_for(self._wait_for_update_login_token(), timeout=time_out)
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
print("QR code expired, Requesting new Qr code...")
|
|
||||||
continue
|
|
||||||
break
|
break
|
||||||
|
|
||||||
if isinstance(signed_in, User):
|
if isinstance(signed_in, User):
|
||||||
return signed_in
|
return signed_in
|
||||||
|
|
||||||
|
while True:
|
||||||
|
first_name = await ainput("Enter first name: ")
|
||||||
|
last_name = await ainput("Enter last name (empty to skip): ")
|
||||||
|
|
||||||
|
try:
|
||||||
|
signed_up = await self.sign_up(
|
||||||
|
self.phone_number,
|
||||||
|
sent_code.phone_code_hash,
|
||||||
|
first_name,
|
||||||
|
last_name
|
||||||
|
)
|
||||||
|
except BadRequest as e:
|
||||||
|
print(e.MESSAGE)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if isinstance(signed_in, TermsOfService):
|
||||||
|
print("\n" + signed_in.text + "\n")
|
||||||
|
await self.accept_terms_of_service(signed_in.id)
|
||||||
|
|
||||||
|
return signed_up
|
||||||
|
|
||||||
def set_parse_mode(self, parse_mode: Optional["enums.ParseMode"]):
|
def set_parse_mode(self, parse_mode: Optional["enums.ParseMode"]):
|
||||||
"""Set the parse mode to be used globally by the client.
|
"""Set the parse mode to be used globally by the client.
|
||||||
|
|
||||||
|
|
@ -825,7 +810,7 @@ class Client(Methods):
|
||||||
if session_empty:
|
if session_empty:
|
||||||
if not self.api_id or not self.api_hash:
|
if not self.api_id or not self.api_hash:
|
||||||
raise AttributeError("The API key is required for new authorizations. "
|
raise AttributeError("The API key is required for new authorizations. "
|
||||||
"More info: https://pyrofork.wulan17.dev/main/start/auth")
|
"More info: https://pyrofork.wulan17.top/main/start/auth")
|
||||||
|
|
||||||
await self.storage.api_id(self.api_id)
|
await self.storage.api_id(self.api_id)
|
||||||
|
|
||||||
|
|
@ -903,7 +888,7 @@ class Client(Methods):
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
if not include:
|
if not include:
|
||||||
for current_root, _, filenames in os.walk(root.replace(".", "/")):
|
for current_root, dirnames, filenames in os.walk(root.replace(".", "/")):
|
||||||
namespace = current_root.replace("/", ".").replace("\\", ".")
|
namespace = current_root.replace("/", ".").replace("\\", ".")
|
||||||
if "__pycache__" in namespace:
|
if "__pycache__" in namespace:
|
||||||
continue
|
continue
|
||||||
|
|
@ -968,7 +953,7 @@ class Client(Methods):
|
||||||
)
|
)
|
||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
except Exception:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
for path, handlers in include:
|
for path, handlers in include:
|
||||||
|
|
@ -1057,7 +1042,7 @@ class Client(Methods):
|
||||||
)
|
)
|
||||||
|
|
||||||
count += 1
|
count += 1
|
||||||
except Exception:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if handlers is None:
|
if handlers is None:
|
||||||
|
|
@ -1121,7 +1106,7 @@ class Client(Methods):
|
||||||
async def handle_download(self, packet):
|
async def handle_download(self, packet):
|
||||||
file_id, directory, file_name, in_memory, file_size, progress, progress_args = packet
|
file_id, directory, file_name, in_memory, file_size, progress, progress_args = packet
|
||||||
|
|
||||||
_ = os.makedirs(directory, exist_ok=True) if not in_memory else None
|
os.makedirs(directory, exist_ok=True) if not in_memory else None
|
||||||
temp_file_path = os.path.abspath(re.sub("\\\\", "/", os.path.join(directory, file_name))) + ".temp"
|
temp_file_path = os.path.abspath(re.sub("\\\\", "/", os.path.join(directory, file_name))) + ".temp"
|
||||||
file = BytesIO() if in_memory else open(temp_file_path, "wb")
|
file = BytesIO() if in_memory else open(temp_file_path, "wb")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,3 @@
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from .connection import Connection
|
from .connection import Connection
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
"Connection"
|
|
||||||
]
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ class Connection:
|
||||||
self.protocol: Optional[TCP] = None
|
self.protocol: Optional[TCP] = None
|
||||||
|
|
||||||
async def connect(self) -> None:
|
async def connect(self) -> None:
|
||||||
for _ in range(Connection.MAX_CONNECTION_ATTEMPTS):
|
for i in range(Connection.MAX_CONNECTION_ATTEMPTS):
|
||||||
self.protocol = self.protocol_factory(ipv6=self.ipv6, proxy=self.proxy)
|
self.protocol = self.protocol_factory(ipv6=self.ipv6, proxy=self.proxy)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,3 @@
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from .tcp import *
|
from .tcp import *
|
||||||
|
|
||||||
__all__ = []
|
|
||||||
__all__.extend(tcp.__all__)
|
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,3 @@ from .tcp_abridged_o import TCPAbridgedO
|
||||||
from .tcp_full import TCPFull
|
from .tcp_full import TCPFull
|
||||||
from .tcp_intermediate import TCPIntermediate
|
from .tcp_intermediate import TCPIntermediate
|
||||||
from .tcp_intermediate_o import TCPIntermediateO
|
from .tcp_intermediate_o import TCPIntermediateO
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
"TCP",
|
|
||||||
"Proxy",
|
|
||||||
"TCPAbridged",
|
|
||||||
"TCPAbridgedO",
|
|
||||||
"TCPFull",
|
|
||||||
"TCPIntermediate",
|
|
||||||
"TCPIntermediateO"
|
|
||||||
]
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import asyncio
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from typing import Tuple, Dict, TypedDict, Optional
|
from typing import Tuple, Dict, TypedDict, Optional
|
||||||
|
|
||||||
import socks
|
import socks
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ except ImportError:
|
||||||
log.warning(
|
log.warning(
|
||||||
"TgCrypto is missing! "
|
"TgCrypto is missing! "
|
||||||
"Pyrogram will work the same, but at a much slower speed. "
|
"Pyrogram will work the same, but at a much slower speed. "
|
||||||
"More info: https://pyrofork.wulan17.dev/main/topics/speedups"
|
"More info: https://pyrofork.wulan17.top/main/topics/speedups"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ def unpack(
|
||||||
message = Message.read(data)
|
message = Message.read(data)
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
if e.args[0] == 0:
|
if e.args[0] == 0:
|
||||||
raise ConnectionError("Received empty data. Check your internet connection.")
|
raise ConnectionError(f"Received empty data. Check your internet connection.")
|
||||||
|
|
||||||
left = data.read().hex()
|
left = data.read().hex()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ def decompose(pq: int) -> int:
|
||||||
while g == 1:
|
while g == 1:
|
||||||
x = y
|
x = y
|
||||||
|
|
||||||
for _ in range(r):
|
for i in range(r):
|
||||||
y = (pow(y, 2, pq) + c) % pq
|
y = (pow(y, 2, pq) + c) % pq
|
||||||
|
|
||||||
k = 0
|
k = 0
|
||||||
|
|
@ -63,7 +63,7 @@ def decompose(pq: int) -> int:
|
||||||
while k < r and g == 1:
|
while k < r and g == 1:
|
||||||
ys = y
|
ys = y
|
||||||
|
|
||||||
for _ in range(min(m, r - k)):
|
for i in range(min(m, r - k)):
|
||||||
y = (pow(y, 2, pq) + c) % pq
|
y = (pow(y, 2, pq) + c) % pq
|
||||||
q = q * (abs(x - y)) % pq
|
q = q * (abs(x - y)) % pq
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,9 @@ import asyncio
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw, types, utils
|
from pyrogram import errors, raw, types, utils
|
||||||
from pyrogram.handlers.handler import Handler
|
from pyrogram.handlers.handler import Handler
|
||||||
from pyrogram.handlers import (
|
from pyrogram.handlers import (
|
||||||
BotBusinessConnectHandler,
|
BotBusinessConnectHandler,
|
||||||
|
|
@ -95,12 +94,7 @@ class Dispatcher:
|
||||||
|
|
||||||
def __init__(self, client: "pyrogram.Client"):
|
def __init__(self, client: "pyrogram.Client"):
|
||||||
self.client = client
|
self.client = client
|
||||||
try:
|
self.loop = asyncio.get_event_loop()
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
except RuntimeError:
|
|
||||||
loop = asyncio.new_event_loop()
|
|
||||||
asyncio.set_event_loop(loop)
|
|
||||||
self.loop = loop
|
|
||||||
|
|
||||||
self.handler_worker_tasks = []
|
self.handler_worker_tasks = []
|
||||||
self.locks_list = []
|
self.locks_list = []
|
||||||
|
|
@ -272,7 +266,7 @@ class Dispatcher:
|
||||||
|
|
||||||
async def start(self):
|
async def start(self):
|
||||||
if not self.client.no_updates:
|
if not self.client.no_updates:
|
||||||
for _ in range(self.client.workers):
|
for i in range(self.client.workers):
|
||||||
self.locks_list.append(asyncio.Lock())
|
self.locks_list.append(asyncio.Lock())
|
||||||
|
|
||||||
self.handler_worker_tasks.append(
|
self.handler_worker_tasks.append(
|
||||||
|
|
@ -343,88 +337,59 @@ class Dispatcher:
|
||||||
async def handler_worker(self, lock: asyncio.Lock):
|
async def handler_worker(self, lock: asyncio.Lock):
|
||||||
while True:
|
while True:
|
||||||
packet = await self.updates_queue.get()
|
packet = await self.updates_queue.get()
|
||||||
|
|
||||||
if packet is None:
|
if packet is None:
|
||||||
break
|
break
|
||||||
|
await self._process_packet(packet, lock)
|
||||||
|
|
||||||
try:
|
async def _process_packet(
|
||||||
await self._handle_packet(packet, lock)
|
self,
|
||||||
except pyrogram.StopPropagation:
|
packet: tuple[raw.core.TLObject, dict[int, types.Update], dict[int, types.Update]],
|
||||||
pass
|
lock: asyncio.Lock,
|
||||||
except Exception as e:
|
|
||||||
log.exception(e)
|
|
||||||
finally:
|
|
||||||
self.updates_queue.task_done()
|
|
||||||
|
|
||||||
async def _handle_packet(self, packet, lock: asyncio.Lock):
|
|
||||||
update, users, chats = packet
|
|
||||||
parser = self.update_parsers.get(type(update))
|
|
||||||
|
|
||||||
parsed_update, handler_type = (
|
|
||||||
await parser(update, users, chats)
|
|
||||||
if parser is not None else (None, type(None))
|
|
||||||
)
|
|
||||||
async with lock:
|
|
||||||
await self._dispatch_to_handlers(update, users, chats, parsed_update, handler_type)
|
|
||||||
|
|
||||||
|
|
||||||
async def _dispatch_to_handlers(
|
|
||||||
self, update, users, chats, parsed_update, handler_type,
|
|
||||||
):
|
|
||||||
for group in self.groups.values():
|
|
||||||
for handler in group:
|
|
||||||
args = await self._match_handler(
|
|
||||||
handler, update, users, chats, parsed_update, handler_type,
|
|
||||||
)
|
|
||||||
if args is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
|
||||||
await self._execute_handler(handler, *args)
|
|
||||||
except pyrogram.StopPropagation:
|
|
||||||
raise
|
|
||||||
except pyrogram.ContinuePropagation:
|
|
||||||
continue
|
|
||||||
except Exception as error:
|
|
||||||
if parsed_update is not None:
|
|
||||||
await self._handle_exception(parsed_update, error)
|
|
||||||
break
|
|
||||||
|
|
||||||
async def _match_handler(
|
|
||||||
self, handler, update, users, chats, parsed_update, handler_type,
|
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
if isinstance(handler, handler_type):
|
update, users, chats = packet
|
||||||
if await handler.check(self.client, parsed_update):
|
parser = self.update_parsers.get(type(update))
|
||||||
return (parsed_update,)
|
|
||||||
elif isinstance(handler, RawUpdateHandler):
|
if parser is not None:
|
||||||
if await handler.check(self.client, update):
|
parsed_result = parser(update, users, chats)
|
||||||
return (update, users, chats)
|
if inspect.isawaitable(parsed_result):
|
||||||
|
parsed_update, handler_type = await parsed_result
|
||||||
|
else:
|
||||||
|
parsed_update, handler_type = parsed_result
|
||||||
|
else:
|
||||||
|
parsed_update, handler_type = (None, type(None))
|
||||||
|
|
||||||
|
async with lock:
|
||||||
|
for group in self.groups.values():
|
||||||
|
for handler in group:
|
||||||
|
try:
|
||||||
|
if parsed_update is not None:
|
||||||
|
if isinstance(handler, handler_type) and await handler.check(
|
||||||
|
self.client, parsed_update
|
||||||
|
):
|
||||||
|
await self._execute_callback(handler, parsed_update)
|
||||||
|
break
|
||||||
|
elif isinstance(handler, RawUpdateHandler):
|
||||||
|
await self._execute_callback(handler, update, users, chats)
|
||||||
|
break
|
||||||
|
except (pyrogram.StopPropagation, pyrogram.ContinuePropagation) as e:
|
||||||
|
if isinstance(e, pyrogram.StopPropagation):
|
||||||
|
raise
|
||||||
|
except Exception as exception:
|
||||||
|
if parsed_update is not None:
|
||||||
|
await self._handle_exception(parsed_update, exception)
|
||||||
|
except pyrogram.StopPropagation:
|
||||||
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
|
finally:
|
||||||
|
self.updates_queue.task_done()
|
||||||
|
|
||||||
return None
|
async def _handle_exception(self, parsed_update: types.Update, exception: Exception):
|
||||||
|
|
||||||
async def _execute_handler(self, handler, *args: Any):
|
|
||||||
if inspect.iscoroutinefunction(handler.callback):
|
|
||||||
await handler.callback(self.client, *args)
|
|
||||||
else:
|
|
||||||
await self.loop.run_in_executor(
|
|
||||||
self.client.executor,
|
|
||||||
handler.callback,
|
|
||||||
self.client,
|
|
||||||
*args
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _handle_exception(
|
|
||||||
self, parsed_update: types.Update, exception: Exception,
|
|
||||||
):
|
|
||||||
handled_error = False
|
handled_error = False
|
||||||
for error_handler in self.error_handlers:
|
for error_handler in self.error_handlers:
|
||||||
try:
|
try:
|
||||||
if await error_handler.check(
|
if await error_handler.check(self.client, parsed_update, exception):
|
||||||
self.client, parsed_update, exception,
|
|
||||||
):
|
|
||||||
handled_error = True
|
handled_error = True
|
||||||
break
|
break
|
||||||
except pyrogram.StopPropagation:
|
except pyrogram.StopPropagation:
|
||||||
|
|
@ -436,3 +401,11 @@ class Dispatcher:
|
||||||
|
|
||||||
if not handled_error:
|
if not handled_error:
|
||||||
log.exception("Unhandled exception: %s", exception)
|
log.exception("Unhandled exception: %s", exception)
|
||||||
|
|
||||||
|
async def _execute_callback(self, handler: Handler, *args):
|
||||||
|
if inspect.iscoroutinefunction(handler.callback):
|
||||||
|
await handler.callback(self.client, *args)
|
||||||
|
else:
|
||||||
|
await self.client.loop.run_in_executor(
|
||||||
|
self.client.executor, handler.callback, self.client, *args
|
||||||
|
)
|
||||||
|
|
@ -27,11 +27,9 @@ from .chat_type import ChatType
|
||||||
from .client_platform import ClientPlatform
|
from .client_platform import ClientPlatform
|
||||||
from .folder_color import FolderColor
|
from .folder_color import FolderColor
|
||||||
from .gift_attribute_type import GiftAttributeType
|
from .gift_attribute_type import GiftAttributeType
|
||||||
from .gift_for_resale_order import GiftForResaleOrder
|
|
||||||
from .listerner_types import ListenerTypes
|
from .listerner_types import ListenerTypes
|
||||||
from .message_entity_type import MessageEntityType
|
from .message_entity_type import MessageEntityType
|
||||||
from .message_media_type import MessageMediaType
|
from .message_media_type import MessageMediaType
|
||||||
from .message_origin_type import MessageOriginType
|
|
||||||
from .message_service_type import MessageServiceType
|
from .message_service_type import MessageServiceType
|
||||||
from .messages_filter import MessagesFilter
|
from .messages_filter import MessagesFilter
|
||||||
from .next_code_type import NextCodeType
|
from .next_code_type import NextCodeType
|
||||||
|
|
@ -56,11 +54,9 @@ __all__ = [
|
||||||
'ClientPlatform',
|
'ClientPlatform',
|
||||||
'FolderColor',
|
'FolderColor',
|
||||||
'GiftAttributeType',
|
'GiftAttributeType',
|
||||||
'GiftForResaleOrder',
|
|
||||||
'ListenerTypes',
|
'ListenerTypes',
|
||||||
'MessageEntityType',
|
'MessageEntityType',
|
||||||
'MessageMediaType',
|
'MessageMediaType',
|
||||||
'MessageOriginType',
|
|
||||||
'MessageServiceType',
|
'MessageServiceType',
|
||||||
'MessagesFilter',
|
'MessagesFilter',
|
||||||
'NextCodeType',
|
'NextCodeType',
|
||||||
|
|
|
||||||
|
|
@ -35,13 +35,13 @@ class ChatEventAction(AutoName):
|
||||||
"The linked chat has been changed (see ``old_linked_chat`` and ``new_linked_chat``)"
|
"The linked chat has been changed (see ``old_linked_chat`` and ``new_linked_chat``)"
|
||||||
|
|
||||||
# LOCATION_CHANGED = auto()
|
# LOCATION_CHANGED = auto()
|
||||||
# ""
|
""
|
||||||
|
|
||||||
PHOTO_CHANGED = auto()
|
PHOTO_CHANGED = auto()
|
||||||
"The chat photo has been changed (see ``old_photo`` and ``new_photo``)"
|
"The chat photo has been changed (see ``old_photo`` and ``new_photo``)"
|
||||||
|
|
||||||
# STICKER_SET_CHANGED = auto()
|
# STICKER_SET_CHANGED = auto()
|
||||||
# ""
|
""
|
||||||
|
|
||||||
TITLE_CHANGED = auto()
|
TITLE_CHANGED = auto()
|
||||||
"the chat title has been changed (see ``old_title`` and ``new_title``)"
|
"the chat title has been changed (see ``old_title`` and ``new_title``)"
|
||||||
|
|
@ -56,7 +56,7 @@ class ChatEventAction(AutoName):
|
||||||
"a message has been deleted (see ``deleted_message``)"
|
"a message has been deleted (see ``deleted_message``)"
|
||||||
|
|
||||||
# VOICE_CHAT_DISCARDED = auto()
|
# VOICE_CHAT_DISCARDED = auto()
|
||||||
# ""
|
""
|
||||||
|
|
||||||
MESSAGE_EDITED = auto()
|
MESSAGE_EDITED = auto()
|
||||||
"a message has been edited (see ``old_message`` and ``new_message``)"
|
"a message has been edited (see ``old_message`` and ``new_message``)"
|
||||||
|
|
@ -77,13 +77,13 @@ class ChatEventAction(AutoName):
|
||||||
"a member joined by themselves. (see ``user``)"
|
"a member joined by themselves. (see ``user``)"
|
||||||
|
|
||||||
# MEMBER_JOINED_BY_LINK = auto()
|
# MEMBER_JOINED_BY_LINK = auto()
|
||||||
# ""
|
""
|
||||||
|
|
||||||
MEMBER_LEFT = auto()
|
MEMBER_LEFT = auto()
|
||||||
"a member left by themselves. (see ``user``)"
|
"a member left by themselves. (see ``user``)"
|
||||||
|
|
||||||
# MEMBER_MUTED = auto()
|
# MEMBER_MUTED = auto()
|
||||||
# ""
|
""
|
||||||
|
|
||||||
ADMINISTRATOR_PRIVILEGES_CHANGED = auto()
|
ADMINISTRATOR_PRIVILEGES_CHANGED = auto()
|
||||||
"a chat member has been promoted/demoted or their administrator privileges has changed (see ``old_administrator_privileges`` and ``new_administrator_privileges``)"
|
"a chat member has been promoted/demoted or their administrator privileges has changed (see ``old_administrator_privileges`` and ``new_administrator_privileges``)"
|
||||||
|
|
@ -92,19 +92,19 @@ class ChatEventAction(AutoName):
|
||||||
"a chat member has been restricted/unrestricted or banned/unbanned, or their permissions has changed (see ``old_member_permissions`` and ``new_member_permissions``)"
|
"a chat member has been restricted/unrestricted or banned/unbanned, or their permissions has changed (see ``old_member_permissions`` and ``new_member_permissions``)"
|
||||||
|
|
||||||
# MEMBER_UNMUTED = auto()
|
# MEMBER_UNMUTED = auto()
|
||||||
# ""
|
""
|
||||||
|
|
||||||
# MEMBER_VOLUME_CHANGED = auto()
|
# MEMBER_VOLUME_CHANGED = auto()
|
||||||
# ""
|
""
|
||||||
|
|
||||||
# VIDEO_CHAT_STARTED = auto()
|
# VIDEO_CHAT_STARTED = auto()
|
||||||
# ""
|
""
|
||||||
|
|
||||||
POLL_STOPPED = auto()
|
POLL_STOPPED = auto()
|
||||||
"a poll has been stopped (see ``stopped_poll``)"
|
"a poll has been stopped (see ``stopped_poll``)"
|
||||||
|
|
||||||
# VOICE_CHAT_SETTINGS_CHANGED = auto()
|
# VOICE_CHAT_SETTINGS_CHANGED = auto()
|
||||||
# ""
|
""
|
||||||
|
|
||||||
INVITES_ENABLED = auto()
|
INVITES_ENABLED = auto()
|
||||||
"the chat invitation has been enabled or disabled (see ``invites_enabled``)"
|
"the chat invitation has been enabled or disabled (see ``invites_enabled``)"
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,3 @@ class ChatType(AutoName):
|
||||||
|
|
||||||
CHANNEL = auto()
|
CHANNEL = auto()
|
||||||
"Chat is a channel"
|
"Chat is a channel"
|
||||||
|
|
||||||
FORUM = auto()
|
|
||||||
"Chat is a forum"
|
|
||||||
|
|
||||||
MONOFORUM = auto()
|
|
||||||
"Chat is a monoforum"
|
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
# Pyrofork - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrofork.
|
|
||||||
#
|
|
||||||
# Pyrofork is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrofork is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from enum import auto
|
|
||||||
|
|
||||||
from .auto_name import AutoName
|
|
||||||
|
|
||||||
|
|
||||||
class GiftForResaleOrder(AutoName):
|
|
||||||
"""Describes order in which upgraded gifts for resale will be sorted. Used in :meth:`~pyrogram.Client.search_gifts_for_resale`."""
|
|
||||||
|
|
||||||
PRICE = auto()
|
|
||||||
"The gifts will be sorted by their price from the lowest to the highest"
|
|
||||||
|
|
||||||
CHANGE_DATE = auto()
|
|
||||||
"The gifts will be sorted by the last date when their price was changed from the newest to the oldest"
|
|
||||||
|
|
||||||
NUMBER = auto()
|
|
||||||
"The gifts will be sorted by their number from the smallest to the largest"
|
|
||||||
|
|
@ -84,6 +84,3 @@ class MessageMediaType(AutoName):
|
||||||
|
|
||||||
PAID_MEDIA = auto()
|
PAID_MEDIA = auto()
|
||||||
"Paid media"
|
"Paid media"
|
||||||
|
|
||||||
TODO = auto()
|
|
||||||
"To-Do list media"
|
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrogram.
|
|
||||||
#
|
|
||||||
# Pyrogram is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrogram is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from enum import auto
|
|
||||||
|
|
||||||
from .auto_name import AutoName
|
|
||||||
|
|
||||||
|
|
||||||
class MessageOriginType(AutoName):
|
|
||||||
"""Message origin type enumeration used in :obj:`~pyrogram.types.MessageOrigin`."""
|
|
||||||
|
|
||||||
CHANNEL = auto()
|
|
||||||
"The message was originally a post in a channel"
|
|
||||||
|
|
||||||
CHAT = auto()
|
|
||||||
"The message was originally sent on behalf of a chat"
|
|
||||||
|
|
||||||
HIDDEN_USER = auto()
|
|
||||||
"The message was originally sent by a user, which is hidden by their privacy settings"
|
|
||||||
|
|
||||||
IMPORT = auto()
|
|
||||||
"The message was imported from a foreign chat service"
|
|
||||||
|
|
||||||
|
|
||||||
USER = auto()
|
|
||||||
"The message was originally sent by a known user"
|
|
||||||
|
|
@ -132,12 +132,3 @@ class MessageServiceType(AutoName):
|
||||||
|
|
||||||
SCREENSHOT_TAKEN = auto()
|
SCREENSHOT_TAKEN = auto()
|
||||||
"Screenshot taken"
|
"Screenshot taken"
|
||||||
|
|
||||||
PAID_MESSAGE_PRICE_CHANGED = auto()
|
|
||||||
"Paid message price changed"
|
|
||||||
|
|
||||||
TODO_TASKS_ADDED = auto()
|
|
||||||
"To-Do tasks added"
|
|
||||||
|
|
||||||
TODO_TASKS_COMPLETION = auto()
|
|
||||||
"To-Do tasks completion/incompletion"
|
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,9 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
EXCEPTION_AVAIL = False
|
from .exceptions import *
|
||||||
try:
|
|
||||||
from .exceptions import *
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
EXCEPTION_AVAIL = True
|
|
||||||
from .pyromod import *
|
from .pyromod import *
|
||||||
from .rpc_error import RPCError, UnknownError
|
from .rpc_error import UnknownError
|
||||||
|
|
||||||
|
|
||||||
class BadMsgNotification(Exception):
|
class BadMsgNotification(Exception):
|
||||||
|
|
@ -71,15 +65,3 @@ class CDNFileHashMismatch(SecurityError):
|
||||||
|
|
||||||
def __init__(self, msg: str = None):
|
def __init__(self, msg: str = None):
|
||||||
super().__init__("A CDN file hash mismatch has occurred." if msg is None else msg)
|
super().__init__("A CDN file hash mismatch has occurred." if msg is None else msg)
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
"BadMsgNotification",
|
|
||||||
"SecurityError",
|
|
||||||
"SecurityCheckMismatch",
|
|
||||||
"CDNFileHashMismatch",
|
|
||||||
"RPCError",
|
|
||||||
"UnknownError"
|
|
||||||
]
|
|
||||||
if EXCEPTION_AVAIL:
|
|
||||||
__all__.extend(exceptions.__all__)
|
|
||||||
__all__.extend(pyromod.__all__)
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
# Pyrofork - Telegram MTProto API Client Library for Python
|
# Pyrofork - Telegram MTProto API Client Library for Python
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||||
|
|
@ -251,7 +250,7 @@ react = create(reaction_filter)
|
||||||
|
|
||||||
# region forwarded_filter
|
# region forwarded_filter
|
||||||
async def forwarded_filter(_, __, m: Message):
|
async def forwarded_filter(_, __, m: Message):
|
||||||
return bool(m.forward_origin)
|
return bool(m.forward_date)
|
||||||
|
|
||||||
|
|
||||||
forwarded = create(forwarded_filter)
|
forwarded = create(forwarded_filter)
|
||||||
|
|
@ -796,7 +795,7 @@ from_scheduled = create(from_scheduled_filter)
|
||||||
|
|
||||||
# region linked_channel_filter
|
# region linked_channel_filter
|
||||||
async def linked_channel_filter(_, __, m: Message):
|
async def linked_channel_filter(_, __, m: Message):
|
||||||
return bool((m.forward_origin and m.forward_origin.chat) and not m.from_user)
|
return bool(m.forward_from_chat and not m.from_user)
|
||||||
|
|
||||||
|
|
||||||
linked_channel = create(linked_channel_filter)
|
linked_channel = create(linked_channel_filter)
|
||||||
|
|
@ -890,12 +889,7 @@ def command(commands: Union[str, List[str]], prefixes: Union[str, List[str]] = "
|
||||||
command_re = re.compile(r"([\"'])(.*?)(?<!\\)\1|(\S+)")
|
command_re = re.compile(r"([\"'])(.*?)(?<!\\)\1|(\S+)")
|
||||||
|
|
||||||
async def func(flt, client: pyrogram.Client, message: Message):
|
async def func(flt, client: pyrogram.Client, message: Message):
|
||||||
usernames = []
|
|
||||||
username = client.me.username or ""
|
username = client.me.username or ""
|
||||||
if client.me.usernames:
|
|
||||||
usernames.append(username)
|
|
||||||
for user in client.me.usernames:
|
|
||||||
usernames.append(user.username)
|
|
||||||
text = message.text or message.caption
|
text = message.text or message.caption
|
||||||
message.command = None
|
message.command = None
|
||||||
|
|
||||||
|
|
@ -909,24 +903,6 @@ def command(commands: Union[str, List[str]], prefixes: Union[str, List[str]] = "
|
||||||
without_prefix = text[len(prefix):]
|
without_prefix = text[len(prefix):]
|
||||||
|
|
||||||
for cmd in flt.commands:
|
for cmd in flt.commands:
|
||||||
if usernames:
|
|
||||||
for username in usernames:
|
|
||||||
if not re.match(rf"^(?:{cmd}(?:@?{username})?)(?:\s|$)", without_prefix,
|
|
||||||
flags=re.IGNORECASE if not flt.case_sensitive else 0):
|
|
||||||
continue
|
|
||||||
|
|
||||||
without_command = re.sub(rf"{cmd}(?:@?{username})?\s?", "", without_prefix, count=1,
|
|
||||||
flags=re.IGNORECASE if not flt.case_sensitive else 0)
|
|
||||||
|
|
||||||
# match.groups are 1-indexed, group(1) is the quote, group(2) is the text
|
|
||||||
# between the quotes, group(3) is unquoted, whitespace-split text
|
|
||||||
|
|
||||||
# Remove the escape character from the arguments
|
|
||||||
message.command = [cmd] + [
|
|
||||||
re.sub(r"\\([\"'])", r"\1", m.group(2) or m.group(3) or "")
|
|
||||||
for m in command_re.finditer(without_command)
|
|
||||||
]
|
|
||||||
return True
|
|
||||||
if not re.match(rf"^(?:{cmd}(?:@?{username})?)(?:\s|$)", without_prefix,
|
if not re.match(rf"^(?:{cmd}(?:@?{username})?)(?:\s|$)", without_prefix,
|
||||||
flags=re.IGNORECASE if not flt.case_sensitive else 0):
|
flags=re.IGNORECASE if not flt.case_sensitive else 0):
|
||||||
continue
|
continue
|
||||||
|
|
@ -1034,22 +1010,12 @@ class user(Filter, set):
|
||||||
)
|
)
|
||||||
|
|
||||||
async def __call__(self, _, message: Message):
|
async def __call__(self, _, message: Message):
|
||||||
is_usernames_in_filters = False
|
|
||||||
if message.from_user and message.from_user.usernames:
|
|
||||||
for username in message.from_user.usernames:
|
|
||||||
if (
|
|
||||||
username.username in self
|
|
||||||
or username.username.lower() in self
|
|
||||||
):
|
|
||||||
is_usernames_in_filters = True
|
|
||||||
break
|
|
||||||
return (message.from_user
|
return (message.from_user
|
||||||
and (message.from_user.id in self
|
and (message.from_user.id in self
|
||||||
or (message.from_user.username
|
or (message.from_user.username
|
||||||
and message.from_user.username.lower() in self)
|
and message.from_user.username.lower() in self)
|
||||||
or ("me" in self
|
or ("me" in self
|
||||||
and message.from_user.is_self))
|
and message.from_user.is_self)))
|
||||||
or is_usernames_in_filters)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
|
|
@ -1077,15 +1043,6 @@ class chat(Filter, set):
|
||||||
|
|
||||||
async def __call__(self, _, message: Union[Message, Story]):
|
async def __call__(self, _, message: Union[Message, Story]):
|
||||||
if isinstance(message, Story):
|
if isinstance(message, Story):
|
||||||
is_usernames_in_filters = False
|
|
||||||
if message.sender_chat and message.sender_chat.usernames:
|
|
||||||
for username in message.sender_chat.usernames:
|
|
||||||
if (
|
|
||||||
username.username in self
|
|
||||||
or username.username.lower() in self
|
|
||||||
):
|
|
||||||
is_usernames_in_filters = True
|
|
||||||
break
|
|
||||||
return (
|
return (
|
||||||
message.sender_chat
|
message.sender_chat
|
||||||
and (
|
and (
|
||||||
|
|
@ -1104,17 +1061,8 @@ class chat(Filter, set):
|
||||||
and message.from_user.username.lower() in self
|
and message.from_user.username.lower() in self
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
) or is_usernames_in_filters
|
)
|
||||||
else:
|
else:
|
||||||
is_usernames_in_filters = False
|
|
||||||
if message.chat and message.chat.usernames:
|
|
||||||
for username in message.chat.usernames:
|
|
||||||
if (
|
|
||||||
username.username in self
|
|
||||||
or username.username.lower() in self
|
|
||||||
):
|
|
||||||
is_usernames_in_filters = True
|
|
||||||
break
|
|
||||||
return (message.chat
|
return (message.chat
|
||||||
and (message.chat.id in self
|
and (message.chat.id in self
|
||||||
or (message.chat.username
|
or (message.chat.username
|
||||||
|
|
@ -1122,10 +1070,7 @@ class chat(Filter, set):
|
||||||
or ("me" in self
|
or ("me" in self
|
||||||
and message.from_user
|
and message.from_user
|
||||||
and message.from_user.is_self
|
and message.from_user.is_self
|
||||||
and not message.outgoing))
|
and not message.outgoing)))
|
||||||
or (is_usernames_in_filters
|
|
||||||
and not message.outgoing)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyPep8Naming
|
# noinspection PyPep8Naming
|
||||||
|
|
@ -1136,7 +1081,6 @@ class topic(Filter, set):
|
||||||
Parameters:
|
Parameters:
|
||||||
topics (``int`` | ``list``):
|
topics (``int`` | ``list``):
|
||||||
Pass one or more topic ids to filter messages in specific topics.
|
Pass one or more topic ids to filter messages in specific topics.
|
||||||
Pass 1 for general topic.
|
|
||||||
Defaults to None (no topics).
|
Defaults to None (no topics).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -1148,6 +1092,4 @@ class topic(Filter, set):
|
||||||
)
|
)
|
||||||
|
|
||||||
async def __call__(self, _, message: Message):
|
async def __call__(self, _, message: Message):
|
||||||
if message.is_topic_message and not message.topic:
|
|
||||||
return 1 in self
|
|
||||||
return message.topic and message.topic.id in self
|
return message.topic and message.topic.id in self
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ from .error_handler import ErrorHandler
|
||||||
from .inline_query_handler import InlineQueryHandler
|
from .inline_query_handler import InlineQueryHandler
|
||||||
from .message_handler import MessageHandler
|
from .message_handler import MessageHandler
|
||||||
from .poll_handler import PollHandler
|
from .poll_handler import PollHandler
|
||||||
|
from .pre_checkout_query_handler import PreCheckoutQueryHandler
|
||||||
from .purchased_paid_media_handler import PurchasedPaidMediaHandler
|
from .purchased_paid_media_handler import PurchasedPaidMediaHandler
|
||||||
from .raw_update_handler import RawUpdateHandler
|
from .raw_update_handler import RawUpdateHandler
|
||||||
from .user_status_handler import UserStatusHandler
|
from .user_status_handler import UserStatusHandler
|
||||||
|
|
@ -41,31 +42,3 @@ from .message_reaction_updated_handler import MessageReactionUpdatedHandler
|
||||||
from .message_reaction_count_updated_handler import MessageReactionCountUpdatedHandler
|
from .message_reaction_count_updated_handler import MessageReactionCountUpdatedHandler
|
||||||
from .pre_checkout_query_handler import PreCheckoutQueryHandler
|
from .pre_checkout_query_handler import PreCheckoutQueryHandler
|
||||||
from .shipping_query_handler import ShippingQueryHandler
|
from .shipping_query_handler import ShippingQueryHandler
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
"BotBusinessConnectHandler",
|
|
||||||
"BotBusinessMessageHandler",
|
|
||||||
"CallbackQueryHandler",
|
|
||||||
"ChatJoinRequestHandler",
|
|
||||||
"ChatMemberUpdatedHandler",
|
|
||||||
"ConversationHandler",
|
|
||||||
"ChosenInlineResultHandler",
|
|
||||||
"DeletedMessagesHandler",
|
|
||||||
"DeletedBotBusinessMessagesHandler",
|
|
||||||
"DisconnectHandler",
|
|
||||||
"EditedMessageHandler",
|
|
||||||
"EditedBotBusinessMessageHandler",
|
|
||||||
"ErrorHandler",
|
|
||||||
"InlineQueryHandler",
|
|
||||||
"MessageHandler",
|
|
||||||
"PollHandler",
|
|
||||||
"PreCheckoutQueryHandler",
|
|
||||||
"PurchasedPaidMediaHandler",
|
|
||||||
"RawUpdateHandler",
|
|
||||||
"UserStatusHandler",
|
|
||||||
"StoryHandler",
|
|
||||||
"MessageReactionUpdatedHandler",
|
|
||||||
"MessageReactionCountUpdatedHandler",
|
|
||||||
"PreCheckoutQueryHandler",
|
|
||||||
"ShippingQueryHandler",
|
|
||||||
]
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,6 @@ class ConversationHandler(MessageHandler, CallbackQueryHandler):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
# pylint: disable=method-hidden
|
|
||||||
async def callback(_, __):
|
async def callback(_, __):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,4 +58,5 @@ class DeletedBotBusinessMessagesHandler(Handler):
|
||||||
for message in messages:
|
for message in messages:
|
||||||
if await super().check(client, message):
|
if await super().check(client, message):
|
||||||
return True
|
return True
|
||||||
return False
|
else:
|
||||||
|
return False
|
||||||
|
|
|
||||||
|
|
@ -58,4 +58,5 @@ class DeletedMessagesHandler(Handler):
|
||||||
for message in messages:
|
for message in messages:
|
||||||
if await super().check(client, message):
|
if await super().check(client, message):
|
||||||
return True
|
return True
|
||||||
return False
|
else:
|
||||||
|
return False
|
||||||
|
|
|
||||||
|
|
@ -13,15 +13,4 @@ GNU General Public License for more details.
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with pyromod. If not, see <https://www.gnu.org/licenses/>.
|
along with pyromod. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
from .helpers import ikb, bki, ntb, btn, kb, kbtn, array_chunk, force_reply
|
from .helpers import ikb, bki, ntb, btn, kb, kbtn, array_chunk, force_reply
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
"ikb",
|
|
||||||
"bki",
|
|
||||||
"ntb",
|
|
||||||
"btn",
|
|
||||||
"kb",
|
|
||||||
"kbtn",
|
|
||||||
"array_chunk",
|
|
||||||
"force_reply"
|
|
||||||
]
|
|
||||||
|
|
@ -101,9 +101,9 @@ def kb(rows=None, **kwargs):
|
||||||
line = []
|
line = []
|
||||||
for button in row:
|
for button in row:
|
||||||
button_type = type(button)
|
button_type = type(button)
|
||||||
if isinstance(button_type, str):
|
if button_type == str:
|
||||||
button = KeyboardButton(button)
|
button = KeyboardButton(button)
|
||||||
elif isinstance(button_type, dict):
|
elif button_type == dict:
|
||||||
button = KeyboardButton(**button)
|
button = KeyboardButton(**button)
|
||||||
|
|
||||||
line.append(button)
|
line.append(button)
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,12 @@ from .bots import Bots
|
||||||
from .chats import Chats
|
from .chats import Chats
|
||||||
from .contacts import Contacts
|
from .contacts import Contacts
|
||||||
from .decorators import Decorators
|
from .decorators import Decorators
|
||||||
from .forums import Forums
|
|
||||||
from .invite_links import InviteLinks
|
from .invite_links import InviteLinks
|
||||||
from .messages import Messages
|
from .messages import Messages
|
||||||
from .password import Password
|
from .password import Password
|
||||||
from .pyromod import Pyromod
|
from .pyromod import Pyromod
|
||||||
from .stickers import Stickers
|
from .stickers import Stickers
|
||||||
from .payments import Payments
|
from .payments import Payments
|
||||||
from .phone import Phone
|
|
||||||
from .users import Users
|
from .users import Users
|
||||||
from .utilities import Utilities
|
from .utilities import Utilities
|
||||||
from .business import TelegramBusiness
|
from .business import TelegramBusiness
|
||||||
|
|
@ -44,9 +42,7 @@ class Methods(
|
||||||
Password,
|
Password,
|
||||||
Pyromod,
|
Pyromod,
|
||||||
Payments,
|
Payments,
|
||||||
Phone,
|
|
||||||
Chats,
|
Chats,
|
||||||
Forums,
|
|
||||||
Stickers,
|
Stickers,
|
||||||
Users,
|
Users,
|
||||||
Messages,
|
Messages,
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import inspect
|
||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
|
import os
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from pathlib import PurePath
|
from pathlib import PurePath
|
||||||
from typing import Union, BinaryIO, Callable
|
from typing import Union, BinaryIO, Callable
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from .accept_terms_of_service import AcceptTermsOfService
|
||||||
from .check_password import CheckPassword
|
from .check_password import CheckPassword
|
||||||
from .connect import Connect
|
from .connect import Connect
|
||||||
from .disconnect import Disconnect
|
from .disconnect import Disconnect
|
||||||
|
|
@ -30,11 +31,12 @@ from .send_code import SendCode
|
||||||
from .send_recovery_code import SendRecoveryCode
|
from .send_recovery_code import SendRecoveryCode
|
||||||
from .sign_in import SignIn
|
from .sign_in import SignIn
|
||||||
from .sign_in_bot import SignInBot
|
from .sign_in_bot import SignInBot
|
||||||
from .sign_in_qrcode import SignInQrcode
|
from .sign_up import SignUp
|
||||||
from .terminate import Terminate
|
from .terminate import Terminate
|
||||||
|
|
||||||
|
|
||||||
class Auth(
|
class Auth(
|
||||||
|
AcceptTermsOfService,
|
||||||
CheckPassword,
|
CheckPassword,
|
||||||
Connect,
|
Connect,
|
||||||
Disconnect,
|
Disconnect,
|
||||||
|
|
@ -48,7 +50,7 @@ class Auth(
|
||||||
SendRecoveryCode,
|
SendRecoveryCode,
|
||||||
SignIn,
|
SignIn,
|
||||||
SignInBot,
|
SignInBot,
|
||||||
SignInQrcode,
|
SignUp,
|
||||||
Terminate
|
Terminate
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
# Pyrofork - Telegram MTProto API Client Library for Python
|
# Pyrofork - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||||
#
|
#
|
||||||
# This file is part of Pyrofork.
|
# This file is part of Pyrofork.
|
||||||
|
|
@ -16,31 +17,29 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from typing import List, Union
|
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
|
|
||||||
|
|
||||||
class GetSimilarBots:
|
class AcceptTermsOfService:
|
||||||
async def get_similar_bots(
|
async def accept_terms_of_service(
|
||||||
self: "pyrogram.Client",
|
self: "pyrogram.Client",
|
||||||
bot: Union[int, str]
|
terms_of_service_id: str
|
||||||
) -> List["pyrogram.types.User"]:
|
) -> bool:
|
||||||
"""Get a list of bots similar to the target bot.
|
"""Accept the given terms of service.
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
bot (``int`` | ``str``):
|
terms_of_service_id (``str``):
|
||||||
Unique identifier (int) or username (str) of the target bot.
|
The terms of service identifier.
|
||||||
|
|
||||||
Returns:
|
|
||||||
List of :obj:`~pyrogram.types.User`: On success.
|
|
||||||
"""
|
"""
|
||||||
peer = await self.resolve_peer(bot)
|
r = await self.invoke(
|
||||||
r = await self.invoke(raw.functions.bots.GetBotRecommendations(bot=peer))
|
raw.functions.help.AcceptTermsOfService(
|
||||||
return pyrogram.types.List([
|
id=raw.types.DataJSON(
|
||||||
pyrogram.types.User._parse(self, u)
|
data=terms_of_service_id
|
||||||
for u in r.users
|
)
|
||||||
])
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return bool(r)
|
||||||
|
|
@ -35,7 +35,6 @@ class Connect:
|
||||||
Raises:
|
Raises:
|
||||||
ConnectionError: In case you try to connect an already connected client.
|
ConnectionError: In case you try to connect an already connected client.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=access-member-before-definition
|
|
||||||
if self.is_connected:
|
if self.is_connected:
|
||||||
raise ConnectionError("Client is already connected")
|
raise ConnectionError("Client is already connected")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ class Disconnect:
|
||||||
ConnectionError: In case you try to disconnect an already disconnected client or in case you try to
|
ConnectionError: In case you try to disconnect an already disconnected client or in case you try to
|
||||||
disconnect a client that needs to be terminated first.
|
disconnect a client that needs to be terminated first.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=access-member-before-definition
|
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise ConnectionError("Client is already disconnected")
|
raise ConnectionError("Client is already disconnected")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw, types
|
from pyrogram import raw, types
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ class Initialize:
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise ConnectionError("Can't initialize a disconnected client")
|
raise ConnectionError("Can't initialize a disconnected client")
|
||||||
|
|
||||||
# pylint: disable=access-member-before-definition
|
|
||||||
if self.is_initialized:
|
if self.is_initialized:
|
||||||
raise ConnectionError("Client is already initialized")
|
raise ConnectionError("Client is already initialized")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,6 @@ class SendCode:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except (PhoneMigrate, NetworkMigrate) as e:
|
except (PhoneMigrate, NetworkMigrate) as e:
|
||||||
# pylint: disable=access-member-before-definition
|
|
||||||
await self.session.stop()
|
await self.session.stop()
|
||||||
|
|
||||||
await self.storage.dc_id(e.value)
|
await self.storage.dc_id(e.value)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ from typing import Union
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
from pyrogram import types
|
from pyrogram import types
|
||||||
from pyrogram.errors import PhoneNumberUnoccupied
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -50,13 +49,15 @@ class SignIn:
|
||||||
The valid confirmation code you received (either as Telegram message or as SMS in your phone number).
|
The valid confirmation code you received (either as Telegram message or as SMS in your phone number).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:obj:`~pyrogram.types.User` | bool: On success, in case the
|
:obj:`~pyrogram.types.User` | :obj:`~pyrogram.types.TermsOfService` | bool: On success, in case the
|
||||||
authorization completed, the user is returned.
|
authorization completed, the user is returned. In case the phone number needs to be registered first AND the
|
||||||
|
terms of services accepted (with :meth:`~pyrogram.Client.accept_terms_of_service`), an object containing
|
||||||
|
them is returned. In case the phone number needs to be registered, but the terms of services don't need to
|
||||||
|
be accepted, False is returned instead.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
BadRequest: In case the arguments are invalid.
|
BadRequest: In case the arguments are invalid.
|
||||||
SessionPasswordNeeded: In case a password is needed to sign in.
|
SessionPasswordNeeded: In case a password is needed to sign in.
|
||||||
PhoneNumberUnoccupied: In case the phone number is not registered on Telegram.
|
|
||||||
"""
|
"""
|
||||||
phone_number = phone_number.strip(" +")
|
phone_number = phone_number.strip(" +")
|
||||||
|
|
||||||
|
|
@ -69,7 +70,10 @@ class SignIn:
|
||||||
)
|
)
|
||||||
|
|
||||||
if isinstance(r, raw.types.auth.AuthorizationSignUpRequired):
|
if isinstance(r, raw.types.auth.AuthorizationSignUpRequired):
|
||||||
raise PhoneNumberUnoccupied("The phone number is not registered on Telegram. Please use official Telegram app to register it.")
|
if r.terms_of_service:
|
||||||
|
return types.TermsOfService._parse(terms_of_service=r.terms_of_service)
|
||||||
|
|
||||||
|
return False
|
||||||
else:
|
else:
|
||||||
await self.storage.user_id(r.user.id)
|
await self.storage.user_id(r.user.id)
|
||||||
await self.storage.is_bot(False)
|
await self.storage.is_bot(False)
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,6 @@ class SignInBot:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except UserMigrate as e:
|
except UserMigrate as e:
|
||||||
# pylint: disable=access-member-before-definition
|
|
||||||
await self.session.stop()
|
await self.session.stop()
|
||||||
|
|
||||||
await self.storage.dc_id(e.value)
|
await self.storage.dc_id(e.value)
|
||||||
|
|
|
||||||
|
|
@ -1,111 +0,0 @@
|
||||||
# Pyrofork - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrofork.
|
|
||||||
#
|
|
||||||
# Pyrofork is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrofork is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import logging
|
|
||||||
from base64 import b64encode
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
import pyrogram
|
|
||||||
from pyrogram import raw
|
|
||||||
from pyrogram import types
|
|
||||||
from pyrogram.session import Session, Auth
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class SignInQrcode:
|
|
||||||
async def sign_in_qrcode(
|
|
||||||
self: "pyrogram.Client"
|
|
||||||
) -> Union["types.User", "types.LoginToken"]:
|
|
||||||
"""Authorize a user in Telegram with a QR code.
|
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
:obj:`~pyrogram.types.User` | :obj:`pyrogram.types.LoginToken`, in case the
|
|
||||||
authorization completed, the user is returned. In case the QR code is
|
|
||||||
not scanned, a login token is returned.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ImportError: In case the qrcode library is not installed.
|
|
||||||
SessionPasswordNeeded: In case a password is needed to sign in.
|
|
||||||
"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
import qrcode
|
|
||||||
except ImportError:
|
|
||||||
raise ImportError("qrcode is missing! "
|
|
||||||
"Please install it with `pip install qrcode`")
|
|
||||||
r = await self.session.invoke(
|
|
||||||
raw.functions.auth.ExportLoginToken(
|
|
||||||
api_id=self.api_id,
|
|
||||||
api_hash=self.api_hash,
|
|
||||||
except_ids=[]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if isinstance(r, raw.types.auth.LoginToken):
|
|
||||||
base64_token = b64encode(r.token).decode("utf-8")
|
|
||||||
login_url = f"tg://login?token={base64_token}"
|
|
||||||
qr = qrcode.QRCode(
|
|
||||||
version=1,
|
|
||||||
error_correction=qrcode.constants.ERROR_CORRECT_L,
|
|
||||||
box_size=10,
|
|
||||||
border=4,
|
|
||||||
)
|
|
||||||
qr.add_data(login_url)
|
|
||||||
qr.make(fit=True)
|
|
||||||
|
|
||||||
print("Scan the QR code with your Telegram app.")
|
|
||||||
qr.print_ascii()
|
|
||||||
|
|
||||||
return types.LoginToken._parse(r)
|
|
||||||
if isinstance(r, raw.types.auth.LoginTokenSuccess):
|
|
||||||
await self.storage.user_id(r.authorization.user.id)
|
|
||||||
await self.storage.is_bot(False)
|
|
||||||
|
|
||||||
return types.User._parse(self, r.authorization.user)
|
|
||||||
if isinstance(r, raw.types.auth.LoginTokenMigrateTo):
|
|
||||||
# pylint: disable=access-member-before-definition
|
|
||||||
await self.session.stop()
|
|
||||||
|
|
||||||
await self.storage.dc_id(r.dc_id)
|
|
||||||
await self.storage.auth_key(
|
|
||||||
await Auth(
|
|
||||||
self, await self.storage.dc_id(),
|
|
||||||
await self.storage.test_mode()
|
|
||||||
).create()
|
|
||||||
)
|
|
||||||
self.session = Session(
|
|
||||||
self, await self.storage.dc_id(),
|
|
||||||
await self.storage.auth_key(), await self.storage.test_mode()
|
|
||||||
)
|
|
||||||
|
|
||||||
await self.session.start()
|
|
||||||
r = await self.session.invoke(
|
|
||||||
raw.functions.auth.ImportLoginToken(
|
|
||||||
token=r.token
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if isinstance(r, raw.types.auth.LoginTokenSuccess):
|
|
||||||
await self.storage.user_id(r.authorization.user.id)
|
|
||||||
await self.storage.is_bot(False)
|
|
||||||
|
|
||||||
return types.User._parse(self, r.authorization.user)
|
|
||||||
raise pyrogram.exceptions.RPCError(
|
|
||||||
"Unknown response type from Telegram API"
|
|
||||||
)
|
|
||||||
74
pyrogram/methods/auth/sign_up.py
Normal file
74
pyrogram/methods/auth/sign_up.py
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
# Pyrofork - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
|
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrofork.
|
||||||
|
#
|
||||||
|
# Pyrofork is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrofork is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import pyrogram
|
||||||
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class SignUp:
|
||||||
|
async def sign_up(
|
||||||
|
self: "pyrogram.Client",
|
||||||
|
phone_number: str,
|
||||||
|
phone_code_hash: str,
|
||||||
|
first_name: str,
|
||||||
|
last_name: str = ""
|
||||||
|
) -> "types.User":
|
||||||
|
"""Register a new user in Telegram.
|
||||||
|
|
||||||
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
phone_number (``str``):
|
||||||
|
Phone number in international format (includes the country prefix).
|
||||||
|
|
||||||
|
phone_code_hash (``str``):
|
||||||
|
Code identifier taken from the result of :meth:`~pyrogram.Client.send_code`.
|
||||||
|
|
||||||
|
first_name (``str``):
|
||||||
|
New user first name.
|
||||||
|
|
||||||
|
last_name (``str``, *optional*):
|
||||||
|
New user last name. Defaults to "" (empty string, no last name).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`~pyrogram.types.User`: On success, the new registered user is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
BadRequest: In case the arguments are invalid.
|
||||||
|
"""
|
||||||
|
phone_number = phone_number.strip(" +")
|
||||||
|
|
||||||
|
r = await self.invoke(
|
||||||
|
raw.functions.auth.SignUp(
|
||||||
|
phone_number=phone_number,
|
||||||
|
first_name=first_name,
|
||||||
|
last_name=last_name,
|
||||||
|
phone_code_hash=phone_code_hash
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
await self.storage.user_id(r.user.id)
|
||||||
|
await self.storage.is_bot(False)
|
||||||
|
|
||||||
|
return types.User._parse(self, r.user)
|
||||||
|
|
@ -37,7 +37,6 @@ class Terminate:
|
||||||
Raises:
|
Raises:
|
||||||
ConnectionError: In case you try to terminate a client that is already terminated.
|
ConnectionError: In case you try to terminate a client that is already terminated.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=access-member-before-definition
|
|
||||||
if not self.is_initialized:
|
if not self.is_initialized:
|
||||||
raise ConnectionError("Client is already terminated")
|
raise ConnectionError("Client is already terminated")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ from .set_bot_info import SetBotInfo
|
||||||
from .set_chat_menu_button import SetChatMenuButton
|
from .set_chat_menu_button import SetChatMenuButton
|
||||||
from .set_game_score import SetGameScore
|
from .set_game_score import SetGameScore
|
||||||
from .get_owned_bots import GetOwnedBots
|
from .get_owned_bots import GetOwnedBots
|
||||||
from .get_similar_bots import GetSimilarBots
|
|
||||||
|
|
||||||
|
|
||||||
class Bots(
|
class Bots(
|
||||||
|
|
@ -61,6 +60,5 @@ class Bots(
|
||||||
AnswerWebAppQuery,
|
AnswerWebAppQuery,
|
||||||
GetCollectibleItemInfo,
|
GetCollectibleItemInfo,
|
||||||
GetOwnedBots,
|
GetOwnedBots,
|
||||||
GetSimilarBots,
|
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -28,24 +28,17 @@ class GetCollectibleItemInfo:
|
||||||
phone_number: str = None
|
phone_number: str = None
|
||||||
) -> "types.CollectibleInfo":
|
) -> "types.CollectibleInfo":
|
||||||
"""Returns information about a given collectible item that was purchased at https://fragment.com
|
"""Returns information about a given collectible item that was purchased at https://fragment.com
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
You must use exactly one of ``username`` OR ``phone_number``.
|
You must use exactly one of ``username`` OR ``phone_number``.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
username (``str``, *optional*):
|
username (``str``, *optional*):
|
||||||
Describes a collectible username that can be purchased at https://fragment.com
|
Describes a collectible username that can be purchased at https://fragment.com
|
||||||
|
|
||||||
phone_number (``str``, *optional*):
|
phone_number (``str``, *optional*):
|
||||||
Describes a collectible phone number that can be purchased at https://fragment.com
|
Describes a collectible phone number that can be purchased at https://fragment.com
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:obj:`~pyrogram.types.CollectibleInfo`: On success, a collectible info is returned.
|
:obj:`~pyrogram.types.CollectibleInfo`: On success, a collectible info is returned.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
username = await app.get_collectible_item_info(username="nerd")
|
username = await app.get_collectible_item_info(username="nerd")
|
||||||
print(username)
|
print(username)
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -102,17 +102,6 @@ class SendInlineBotResult:
|
||||||
"""
|
"""
|
||||||
quote_text, quote_entities = (await utils.parse_text_entities(self, quote_text, parse_mode, quote_entities)).values()
|
quote_text, quote_entities = (await utils.parse_text_entities(self, quote_text, parse_mode, quote_entities)).values()
|
||||||
|
|
||||||
reply_to = await utils.get_reply_to(
|
|
||||||
client=self,
|
|
||||||
reply_to_message_id=reply_to_message_id,
|
|
||||||
reply_to_chat_id=reply_to_chat_id,
|
|
||||||
reply_to_story_id=reply_to_story_id,
|
|
||||||
message_thread_id=message_thread_id,
|
|
||||||
quote_text=quote_text,
|
|
||||||
quote_entities=quote_entities,
|
|
||||||
quote_offset=quote_offset,
|
|
||||||
parse_mode=parse_mode,
|
|
||||||
)
|
|
||||||
r = await self.invoke(
|
r = await self.invoke(
|
||||||
raw.functions.messages.SendInlineBotResult(
|
raw.functions.messages.SendInlineBotResult(
|
||||||
peer=await self.resolve_peer(chat_id),
|
peer=await self.resolve_peer(chat_id),
|
||||||
|
|
@ -120,7 +109,15 @@ class SendInlineBotResult:
|
||||||
id=result_id,
|
id=result_id,
|
||||||
random_id=self.rnd_id(),
|
random_id=self.rnd_id(),
|
||||||
silent=disable_notification or None,
|
silent=disable_notification or None,
|
||||||
reply_to=reply_to,
|
reply_to=utils.get_reply_to(
|
||||||
|
reply_to_message_id=reply_to_message_id,
|
||||||
|
reply_to_peer=await self.resolve_peer(reply_to_chat_id) if reply_to_chat_id else None,
|
||||||
|
reply_to_story_id=reply_to_story_id,
|
||||||
|
message_thread_id=message_thread_id,
|
||||||
|
quote_text=quote_text,
|
||||||
|
quote_entities=quote_entities,
|
||||||
|
quote_offset=quote_offset,
|
||||||
|
),
|
||||||
schedule_date=utils.datetime_to_timestamp(schedule_date),
|
schedule_date=utils.datetime_to_timestamp(schedule_date),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
#
|
||||||
# This file is part of Pyrogram.
|
# This file is part of Pyrogram.
|
||||||
#
|
#
|
||||||
|
|
@ -19,20 +18,12 @@
|
||||||
|
|
||||||
from .answer_pre_checkout_query import AnswerPreCheckoutQuery
|
from .answer_pre_checkout_query import AnswerPreCheckoutQuery
|
||||||
from .answer_shipping_query import AnswerShippingQuery
|
from .answer_shipping_query import AnswerShippingQuery
|
||||||
from .delete_business_messages import DeleteBusinessMessages
|
|
||||||
from .get_business_connection import GetBusinessConnection
|
from .get_business_connection import GetBusinessConnection
|
||||||
from .get_business_account_gifts import GetBusinessAccountGifts
|
|
||||||
from .get_business_account_star_balance import GetBusinessAccountStarBalance
|
|
||||||
from .transfer_business_account_stars import TransferBusinessAccountStars
|
|
||||||
|
|
||||||
|
|
||||||
class TelegramBusiness(
|
class TelegramBusiness(
|
||||||
AnswerPreCheckoutQuery,
|
AnswerPreCheckoutQuery,
|
||||||
AnswerShippingQuery,
|
AnswerShippingQuery,
|
||||||
DeleteBusinessMessages,
|
|
||||||
GetBusinessConnection,
|
GetBusinessConnection,
|
||||||
GetBusinessAccountGifts,
|
|
||||||
GetBusinessAccountStarBalance,
|
|
||||||
TransferBusinessAccountStars,
|
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrogram.
|
|
||||||
#
|
|
||||||
# Pyrogram is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrogram is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from typing import Iterable, Union
|
|
||||||
|
|
||||||
import pyrogram
|
|
||||||
from pyrogram import raw
|
|
||||||
|
|
||||||
|
|
||||||
class DeleteBusinessMessages:
|
|
||||||
async def delete_business_messages(
|
|
||||||
self: "pyrogram.Client",
|
|
||||||
business_connection_id: str,
|
|
||||||
message_ids: Union[int, Iterable[int]]
|
|
||||||
) -> int:
|
|
||||||
"""Delete messages on behalf of a business account.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Requires the `can_delete_sent_messages` business bot right to delete messages sent by the bot itself,
|
|
||||||
or the `can_delete_all_messages` business bot right to delete any message.
|
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/bots.rst
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
business_connection_id (``str``):
|
|
||||||
Unique identifier of business connection on behalf of which to send the request.
|
|
||||||
|
|
||||||
message_ids (``int`` | Iterable of ``int``):
|
|
||||||
An iterable of message identifiers to delete (integers) or a single message id.
|
|
||||||
All messages must be from the same chat.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
``int``: Amount of affected messages
|
|
||||||
|
|
||||||
Example:
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Delete one message
|
|
||||||
await app.delete_business_messages(connection_id, message_id)
|
|
||||||
|
|
||||||
# Delete multiple messages at once
|
|
||||||
await app.delete_business_messages(connection_id, list_of_message_ids)
|
|
||||||
"""
|
|
||||||
message_ids = list(message_ids) if not isinstance(message_ids, int) else [message_ids]
|
|
||||||
|
|
||||||
r = await self.invoke(
|
|
||||||
raw.functions.messages.DeleteMessages(
|
|
||||||
id=message_ids,
|
|
||||||
revoke=True
|
|
||||||
),
|
|
||||||
business_connection_id=business_connection_id
|
|
||||||
)
|
|
||||||
|
|
||||||
return r.pts_count
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrogram.
|
|
||||||
#
|
|
||||||
# Pyrogram is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrogram is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import pyrogram
|
|
||||||
from pyrogram import raw, types
|
|
||||||
|
|
||||||
|
|
||||||
class GetBusinessAccountGifts:
|
|
||||||
async def get_business_account_gifts(
|
|
||||||
self: "pyrogram.Client",
|
|
||||||
business_connection_id: str,
|
|
||||||
exclude_unsaved: Optional[bool] = None,
|
|
||||||
exclude_saved: Optional[bool] = None,
|
|
||||||
exclude_unlimited: Optional[bool] = None,
|
|
||||||
exclude_limited: Optional[bool] = None,
|
|
||||||
exclude_upgraded: Optional[bool] = None,
|
|
||||||
sort_by_price: Optional[bool] = None,
|
|
||||||
limit: int = 0,
|
|
||||||
offset: str = "",
|
|
||||||
):
|
|
||||||
"""Return the gifts received and owned by a managed business account.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Requires the `can_view_gifts_and_stars` business bot right.
|
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/bots.rst
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
business_connection_id (``str``):
|
|
||||||
Unique identifier of business connection on behalf of which to send the request.
|
|
||||||
|
|
||||||
exclude_unsaved (``bool``, *optional*):
|
|
||||||
Pass True to exclude gifts that aren’t saved to the account’s profile page.
|
|
||||||
|
|
||||||
exclude_saved (``bool``, *optional*):
|
|
||||||
Pass True to exclude gifts that are saved to the account’s profile page.
|
|
||||||
|
|
||||||
exclude_unlimited (``bool``, *optional*):
|
|
||||||
Pass True to exclude gifts that can be purchased an unlimited number of times.
|
|
||||||
|
|
||||||
exclude_limited (``bool``, *optional*):
|
|
||||||
Pass True to exclude gifts that can be purchased a limited number of times.
|
|
||||||
|
|
||||||
exclude_upgraded (``bool``, *optional*):
|
|
||||||
Pass True to exclude upgraded gifts.
|
|
||||||
|
|
||||||
sort_by_price (``bool``, *optional*):
|
|
||||||
Pass True to sort results by gift price instead of send date. Sorting is applied before pagination.
|
|
||||||
|
|
||||||
offset (``str``, *optional*):
|
|
||||||
Offset of the first entry to return as received from the previous request.
|
|
||||||
|
|
||||||
limit (``int``, *optional*):
|
|
||||||
The maximum number of gifts to be returned.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
``Generator``: A generator yielding :obj:`~pyrogram.types.Gift` objects.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
async for gift in app.get_business_account_gifts(connection_id):
|
|
||||||
print(gift)
|
|
||||||
"""
|
|
||||||
current = 0
|
|
||||||
total = abs(limit) or (1 << 31) - 1
|
|
||||||
limit = min(100, total)
|
|
||||||
|
|
||||||
connection_info = await self.get_business_connection(business_connection_id)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
r = await self.invoke(
|
|
||||||
raw.functions.payments.GetSavedStarGifts(
|
|
||||||
peer=await self.resolve_peer(connection_info.user.id),
|
|
||||||
offset=offset,
|
|
||||||
limit=limit,
|
|
||||||
exclude_unsaved=exclude_unsaved,
|
|
||||||
exclude_saved=exclude_saved,
|
|
||||||
exclude_unlimited=exclude_unlimited,
|
|
||||||
exclude_limited=exclude_limited,
|
|
||||||
exclude_unique=exclude_upgraded,
|
|
||||||
sort_by_value=sort_by_price
|
|
||||||
),
|
|
||||||
sleep_threshold=60,
|
|
||||||
business_connection_id=business_connection_id
|
|
||||||
)
|
|
||||||
|
|
||||||
users = {i.id: i for i in r.users}
|
|
||||||
chats = {i.id: i for i in r.chats}
|
|
||||||
|
|
||||||
user_star_gifts = [
|
|
||||||
await types.Gift._parse_saved(self, gift, users, chats)
|
|
||||||
for gift in r.gifts
|
|
||||||
]
|
|
||||||
|
|
||||||
if not user_star_gifts:
|
|
||||||
return
|
|
||||||
|
|
||||||
for gift in user_star_gifts:
|
|
||||||
yield gift
|
|
||||||
|
|
||||||
current += 1
|
|
||||||
|
|
||||||
if current >= total:
|
|
||||||
return
|
|
||||||
|
|
||||||
offset = r.next_offset
|
|
||||||
|
|
||||||
if not offset:
|
|
||||||
return
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrogram.
|
|
||||||
#
|
|
||||||
# Pyrogram is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrogram is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from typing import Optional, Union
|
|
||||||
|
|
||||||
import pyrogram
|
|
||||||
from pyrogram import raw
|
|
||||||
|
|
||||||
|
|
||||||
class GetBusinessAccountStarBalance:
|
|
||||||
async def get_business_account_star_balance(
|
|
||||||
self: "pyrogram.Client",
|
|
||||||
business_connection_id: str,
|
|
||||||
) -> int:
|
|
||||||
"""Return the amount of Telegram Stars owned by a managed business account.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Requires the `can_view_gifts_and_stars` business bot right.
|
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/bots.rst
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
business_connection_id (``str``):
|
|
||||||
Unique identifier of business connection on behalf of which to send the request.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
``int``: On success, the current stars balance is returned.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Get stars balance
|
|
||||||
await app.get_business_account_star_balance("connection_id")
|
|
||||||
"""
|
|
||||||
connection_info = await self.get_business_connection(business_connection_id)
|
|
||||||
|
|
||||||
r = await self.invoke(
|
|
||||||
raw.functions.payments.GetStarsStatus(
|
|
||||||
peer=await self.resolve_peer(connection_info.user.id),
|
|
||||||
),
|
|
||||||
business_connection_id=business_connection_id
|
|
||||||
)
|
|
||||||
|
|
||||||
return r.balance.amount
|
|
||||||
|
|
@ -16,8 +16,11 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Union, List
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import types, raw
|
from pyrogram import types, utils, raw
|
||||||
|
|
||||||
|
|
||||||
class GetBusinessConnection:
|
class GetBusinessConnection:
|
||||||
|
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrogram.
|
|
||||||
#
|
|
||||||
# Pyrogram is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrogram is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import pyrogram
|
|
||||||
from pyrogram import raw
|
|
||||||
|
|
||||||
|
|
||||||
class TransferBusinessAccountStars:
|
|
||||||
async def transfer_business_account_stars(
|
|
||||||
self: "pyrogram.Client",
|
|
||||||
business_connection_id: str,
|
|
||||||
star_count: int,
|
|
||||||
) -> bool:
|
|
||||||
"""Transfers Telegram Stars from the business account balance to the bot’s balance.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Requires the `can_transfer_stars` business bot right.
|
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
business_connection_id (``str``):
|
|
||||||
Unique identifier of the business connection.
|
|
||||||
|
|
||||||
star_count (``int`` | ``str``):
|
|
||||||
Number of Telegram Stars to transfer, 1-10000.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
``bool``: On success, True is returned.
|
|
||||||
"""
|
|
||||||
# Why telegram won't let us just use InputPeerSelf :(
|
|
||||||
if self.me:
|
|
||||||
bot_id = self.me.id
|
|
||||||
else:
|
|
||||||
bot_id = (
|
|
||||||
await self.invoke(raw.functions.users.GetUsers(id=[raw.types.InputPeerSelf()]))
|
|
||||||
)[0].id
|
|
||||||
|
|
||||||
invoice = raw.types.InputInvoiceBusinessBotTransferStars(
|
|
||||||
bot=await self.resolve_peer(bot_id), stars=star_count
|
|
||||||
)
|
|
||||||
|
|
||||||
payment_form = await self.invoke(
|
|
||||||
raw.functions.payments.GetPaymentForm(invoice=invoice),
|
|
||||||
business_connection_id=business_connection_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
await self.invoke(
|
|
||||||
raw.functions.payments.SendStarsForm(
|
|
||||||
form_id=payment_form.form_id,
|
|
||||||
invoice=invoice,
|
|
||||||
),
|
|
||||||
business_connection_id=business_connection_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
@ -21,14 +21,24 @@ from .add_chat_members import AddChatMembers
|
||||||
from .archive_chats import ArchiveChats
|
from .archive_chats import ArchiveChats
|
||||||
from .ban_chat_member import BanChatMember
|
from .ban_chat_member import BanChatMember
|
||||||
from .create_channel import CreateChannel
|
from .create_channel import CreateChannel
|
||||||
|
from .create_forum_topic import CreateForumTopic
|
||||||
from .create_group import CreateGroup
|
from .create_group import CreateGroup
|
||||||
from .create_supergroup import CreateSupergroup
|
from .create_supergroup import CreateSupergroup
|
||||||
|
from .close_forum_topic import CloseForumTopic
|
||||||
|
from .close_general_topic import CloseGeneralTopic
|
||||||
from .delete_channel import DeleteChannel
|
from .delete_channel import DeleteChannel
|
||||||
from .delete_chat_photo import DeleteChatPhoto
|
from .delete_chat_photo import DeleteChatPhoto
|
||||||
from .delete_folder import DeleteFolder
|
from .delete_folder import DeleteFolder
|
||||||
|
from .delete_forum_topic import DeleteForumTopic
|
||||||
from .delete_supergroup import DeleteSupergroup
|
from .delete_supergroup import DeleteSupergroup
|
||||||
from .delete_user_history import DeleteUserHistory
|
from .delete_user_history import DeleteUserHistory
|
||||||
|
from .edit_forum_topic import EditForumTopic
|
||||||
|
from .edit_general_topic import EditGeneralTopic
|
||||||
from .export_folder_link import ExportFolderLink
|
from .export_folder_link import ExportFolderLink
|
||||||
|
from .reopen_forum_topic import ReopenForumTopic
|
||||||
|
from .reopen_general_topic import ReopenGeneralTopic
|
||||||
|
from .hide_general_topic import HideGeneralTopic
|
||||||
|
from .unhide_general_topic import UnhideGeneralTopic
|
||||||
from .get_chat import GetChat
|
from .get_chat import GetChat
|
||||||
from .get_chat_event_log import GetChatEventLog
|
from .get_chat_event_log import GetChatEventLog
|
||||||
from .get_chat_member import GetChatMember
|
from .get_chat_member import GetChatMember
|
||||||
|
|
@ -38,6 +48,8 @@ from .get_chat_online_count import GetChatOnlineCount
|
||||||
from .get_dialogs import GetDialogs
|
from .get_dialogs import GetDialogs
|
||||||
from .get_dialogs_count import GetDialogsCount
|
from .get_dialogs_count import GetDialogsCount
|
||||||
from .get_folders import GetFolders
|
from .get_folders import GetFolders
|
||||||
|
from .get_forum_topics import GetForumTopics
|
||||||
|
from .get_forum_topics_by_id import GetForumTopicsByID
|
||||||
from .get_send_as_chats import GetSendAsChats
|
from .get_send_as_chats import GetSendAsChats
|
||||||
from .join_chat import JoinChat
|
from .join_chat import JoinChat
|
||||||
from .leave_chat import LeaveChat
|
from .leave_chat import LeaveChat
|
||||||
|
|
@ -54,7 +66,6 @@ from .set_chat_title import SetChatTitle
|
||||||
from .set_chat_username import SetChatUsername
|
from .set_chat_username import SetChatUsername
|
||||||
from .set_send_as_chat import SetSendAsChat
|
from .set_send_as_chat import SetSendAsChat
|
||||||
from .set_slow_mode import SetSlowMode
|
from .set_slow_mode import SetSlowMode
|
||||||
from .transfer_chat_ownership import TransferChatOwnership
|
|
||||||
from .unarchive_chats import UnarchiveChats
|
from .unarchive_chats import UnarchiveChats
|
||||||
from .unban_chat_member import UnbanChatMember
|
from .unban_chat_member import UnbanChatMember
|
||||||
from .unpin_all_chat_messages import UnpinAllChatMessages
|
from .unpin_all_chat_messages import UnpinAllChatMessages
|
||||||
|
|
@ -85,16 +96,28 @@ class Chats(
|
||||||
SetChatPermissions,
|
SetChatPermissions,
|
||||||
GetDialogsCount,
|
GetDialogsCount,
|
||||||
GetFolders,
|
GetFolders,
|
||||||
|
GetForumTopics,
|
||||||
|
GetForumTopicsByID,
|
||||||
ArchiveChats,
|
ArchiveChats,
|
||||||
UnarchiveChats,
|
UnarchiveChats,
|
||||||
CreateGroup,
|
CreateGroup,
|
||||||
CreateSupergroup,
|
CreateSupergroup,
|
||||||
CreateChannel,
|
CreateChannel,
|
||||||
|
CreateForumTopic,
|
||||||
|
CloseForumTopic,
|
||||||
|
CloseGeneralTopic,
|
||||||
AddChatMembers,
|
AddChatMembers,
|
||||||
DeleteChannel,
|
DeleteChannel,
|
||||||
DeleteFolder,
|
DeleteFolder,
|
||||||
|
DeleteForumTopic,
|
||||||
DeleteSupergroup,
|
DeleteSupergroup,
|
||||||
|
EditForumTopic,
|
||||||
|
EditGeneralTopic,
|
||||||
ExportFolderLink,
|
ExportFolderLink,
|
||||||
|
ReopenForumTopic,
|
||||||
|
ReopenGeneralTopic,
|
||||||
|
HideGeneralTopic,
|
||||||
|
UnhideGeneralTopic,
|
||||||
SetAdministratorTitle,
|
SetAdministratorTitle,
|
||||||
SetSlowMode,
|
SetSlowMode,
|
||||||
DeleteUserHistory,
|
DeleteUserHistory,
|
||||||
|
|
@ -105,7 +128,6 @@ class Chats(
|
||||||
GetSendAsChats,
|
GetSendAsChats,
|
||||||
SetSendAsChat,
|
SetSendAsChat,
|
||||||
SetChatProtectedContent,
|
SetChatProtectedContent,
|
||||||
TransferChatOwnership,
|
|
||||||
UpdateColor,
|
UpdateColor,
|
||||||
UpdateFolder
|
UpdateFolder
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -117,4 +117,5 @@ class BanChatMember:
|
||||||
{i.id: i for i in r.users},
|
{i.id: i for i in r.users},
|
||||||
{i.id: i for i in r.chats}
|
{i.id: i for i in r.chats}
|
||||||
)
|
)
|
||||||
return True
|
else:
|
||||||
|
return True
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ class CloseForumTopic:
|
||||||
await app.close_forum_topic(chat_id, topic_id)
|
await app.close_forum_topic(chat_id, topic_id)
|
||||||
"""
|
"""
|
||||||
await self.invoke(
|
await self.invoke(
|
||||||
raw.functions.messages.EditForumTopic(
|
raw.functions.channels.EditForumTopic(
|
||||||
channel=await self.resolve_peer(chat_id),
|
channel=await self.resolve_peer(chat_id),
|
||||||
topic_id=topic_id,
|
topic_id=topic_id,
|
||||||
closed=True
|
closed=True
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ class CloseGeneralTopic:
|
||||||
await app.close_general_topic(chat_id)
|
await app.close_general_topic(chat_id)
|
||||||
"""
|
"""
|
||||||
await self.invoke(
|
await self.invoke(
|
||||||
raw.functions.messages.EditForumTopic(
|
raw.functions.channels.EditForumTopic(
|
||||||
channel=await self.resolve_peer(chat_id),
|
channel=await self.resolve_peer(chat_id),
|
||||||
topic_id=1,
|
topic_id=1,
|
||||||
closed=True
|
closed=True
|
||||||
|
|
@ -56,7 +56,7 @@ class CreateForumTopic:
|
||||||
await app.create_forum_topic("Topic Title")
|
await app.create_forum_topic("Topic Title")
|
||||||
"""
|
"""
|
||||||
r = await self.invoke(
|
r = await self.invoke(
|
||||||
raw.functions.messages.CreateForumTopic(
|
raw.functions.channels.CreateForumTopic(
|
||||||
channel=await self.resolve_peer(chat_id),
|
channel=await self.resolve_peer(chat_id),
|
||||||
title=title,
|
title=title,
|
||||||
random_id=self.rnd_id(),
|
random_id=self.rnd_id(),
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ class DeleteForumTopic:
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await self.invoke(
|
await self.invoke(
|
||||||
raw.functions.messages.DeleteTopicHistory(
|
raw.functions.channels.DeleteTopicHistory(
|
||||||
channel=await self.resolve_peer(chat_id),
|
channel=await self.resolve_peer(chat_id),
|
||||||
top_msg_id=topic_id
|
top_msg_id=topic_id
|
||||||
)
|
)
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -56,7 +56,7 @@ class EditForumTopic:
|
||||||
await app.edit_forum_topic(chat_id,topic_id,"New Topic Title")
|
await app.edit_forum_topic(chat_id,topic_id,"New Topic Title")
|
||||||
"""
|
"""
|
||||||
await self.invoke(
|
await self.invoke(
|
||||||
raw.functions.messages.EditForumTopic(
|
raw.functions.channels.EditForumTopic(
|
||||||
channel=await self.resolve_peer(chat_id),
|
channel=await self.resolve_peer(chat_id),
|
||||||
topic_id=topic_id,
|
topic_id=topic_id,
|
||||||
title=title,
|
title=title,
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ class EditGeneralTopic:
|
||||||
await app.edit_general_topic(chat_id,"New Topic Title")
|
await app.edit_general_topic(chat_id,"New Topic Title")
|
||||||
"""
|
"""
|
||||||
await self.invoke(
|
await self.invoke(
|
||||||
raw.functions.messages.EditForumTopic(
|
raw.functions.channels.EditForumTopic(
|
||||||
channel=await self.resolve_peer(chat_id),
|
channel=await self.resolve_peer(chat_id),
|
||||||
topic_id=1,
|
topic_id=1,
|
||||||
title=title
|
title=title
|
||||||
|
|
@ -25,7 +25,7 @@ class ExportFolderLink:
|
||||||
async def export_folder_link(
|
async def export_folder_link(
|
||||||
self: "pyrogram.Client",
|
self: "pyrogram.Client",
|
||||||
folder_id: int
|
folder_id: int
|
||||||
) -> "pyrogram.types.ExportedFolderLink":
|
) -> str:
|
||||||
"""Export link to a user's folder.
|
"""Export link to a user's folder.
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
@ -35,7 +35,7 @@ class ExportFolderLink:
|
||||||
Unique identifier (int) of the target folder.
|
Unique identifier (int) of the target folder.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:obj:`~pyrogram.types.ExportedFolderLink` objects.
|
``str``: On success, a link to the folder as string is returned.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
@ -67,4 +67,4 @@ class ExportFolderLink:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return types.ExportedFolderLink._parse(r)
|
return r.invite.url
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,8 @@ class GetChatMember:
|
||||||
else:
|
else:
|
||||||
if member.user.id == user.user_id:
|
if member.user.id == user.user_id:
|
||||||
return member
|
return member
|
||||||
raise UserNotParticipant
|
else:
|
||||||
|
raise UserNotParticipant
|
||||||
elif isinstance(chat, raw.types.InputPeerChannel):
|
elif isinstance(chat, raw.types.InputPeerChannel):
|
||||||
r = await self.invoke(
|
r = await self.invoke(
|
||||||
raw.functions.channels.GetParticipant(
|
raw.functions.channels.GetParticipant(
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ from typing import AsyncGenerator, Optional
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import types, raw, utils
|
from pyrogram import types, raw, utils
|
||||||
from pyrogram.errors import ChannelPrivate, PeerIdInvalid
|
from pyrogram.errors import ChannelPrivate
|
||||||
|
|
||||||
|
|
||||||
class GetDialogs:
|
class GetDialogs:
|
||||||
|
|
@ -80,7 +80,7 @@ class GetDialogs:
|
||||||
chat_id = utils.get_peer_id(message.peer_id)
|
chat_id = utils.get_peer_id(message.peer_id)
|
||||||
try:
|
try:
|
||||||
messages[chat_id] = await types.Message._parse(self, message, users, chats)
|
messages[chat_id] = await types.Message._parse(self, message, users, chats)
|
||||||
except (ChannelPrivate, PeerIdInvalid):
|
except ChannelPrivate:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
dialogs = []
|
dialogs = []
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ class GetFolders:
|
||||||
users.update({i.id: i for i in r.users})
|
users.update({i.id: i for i in r.users})
|
||||||
chats.update({i.id: i for i in r.chats})
|
chats.update({i.id: i for i in r.chats})
|
||||||
|
|
||||||
folders = types.List([types.Folder._parse(self, folder, users, chats) for folder in raw_folders])
|
folders = types.List(types.Folder._parse(self, folder, users, chats) for folder in raw_folders)
|
||||||
|
|
||||||
if not folders:
|
if not folders:
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,18 @@ from typing import Union, Optional, AsyncGenerator
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
from pyrogram import types
|
from pyrogram import types
|
||||||
|
from pyrogram import utils
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class GetForumTopicsCount:
|
class GetForumTopics:
|
||||||
async def get_forum_topics_count(
|
async def get_forum_topics(
|
||||||
self: "pyrogram.Client",
|
self: "pyrogram.Client",
|
||||||
chat_id: Union[int, str]
|
chat_id: Union[int, str],
|
||||||
|
limit: int = 0
|
||||||
) -> Optional[AsyncGenerator["types.ForumTopic", None]]:
|
) -> Optional[AsyncGenerator["types.ForumTopic", None]]:
|
||||||
"""Get forum topics count from a chat.
|
"""Get one or more topic from a chat.
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
|
|
@ -41,14 +43,18 @@ class GetForumTopicsCount:
|
||||||
Unique identifier (int) or username (str) of the target chat.
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
You can also use chat public link in form of *t.me/<username>* (str).
|
You can also use chat public link in form of *t.me/<username>* (str).
|
||||||
|
|
||||||
|
limit (``int``, *optional*):
|
||||||
|
Limits the number of topics to be retrieved.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
``int``: On success, the count of forum topics is returned.
|
``Generator``: On success, a generator yielding :obj:`~pyrogram.types.ForumTopic` objects is returned.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
# get all forum topics count
|
# get all forum topics
|
||||||
app.get_forum_topics_count(chat_id)
|
async for topic in app.get_forum_topics(chat_id):
|
||||||
|
print(topic)
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: In case of invalid arguments.
|
ValueError: In case of invalid arguments.
|
||||||
|
|
@ -56,8 +62,9 @@ class GetForumTopicsCount:
|
||||||
|
|
||||||
peer = await self.resolve_peer(chat_id)
|
peer = await self.resolve_peer(chat_id)
|
||||||
|
|
||||||
rpc = raw.functions.messages.GetForumTopics(channel=peer, offset_date=0, offset_id=0, offset_topic=0, limit=0)
|
rpc = raw.functions.channels.GetForumTopics(channel=peer, offset_date=0, offset_id=0, offset_topic=0, limit=limit)
|
||||||
|
|
||||||
r = await self.invoke(rpc, sleep_threshold=-1)
|
r = await self.invoke(rpc, sleep_threshold=-1)
|
||||||
|
|
||||||
return r.count
|
for _topic in r.topics:
|
||||||
|
yield types.ForumTopic._parse(_topic)
|
||||||
|
|
@ -23,6 +23,7 @@ from typing import Union, List, Iterable
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
from pyrogram import types
|
from pyrogram import types
|
||||||
|
from pyrogram import utils
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -62,7 +63,7 @@ class GetForumTopicsByID:
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: In case of invalid arguments.
|
ValueError: In case of invalid arguments.
|
||||||
"""
|
"""
|
||||||
ids, _ = (
|
ids, ids_type = (
|
||||||
(topic_ids, int) if topic_ids
|
(topic_ids, int) if topic_ids
|
||||||
else (None, None)
|
else (None, None)
|
||||||
)
|
)
|
||||||
|
|
@ -76,7 +77,7 @@ class GetForumTopicsByID:
|
||||||
ids = list(ids) if is_iterable else [ids]
|
ids = list(ids) if is_iterable else [ids]
|
||||||
ids = [i for i in ids]
|
ids = [i for i in ids]
|
||||||
|
|
||||||
rpc = raw.functions.messages.GetForumTopicsByID(channel=peer, topics=ids)
|
rpc = raw.functions.channels.GetForumTopicsByID(channel=peer, topics=ids)
|
||||||
|
|
||||||
r = await self.invoke(rpc, sleep_threshold=-1)
|
r = await self.invoke(rpc, sleep_threshold=-1)
|
||||||
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -43,7 +44,7 @@ class HideGeneralTopic:
|
||||||
await app.hide_general_topic(chat_id)
|
await app.hide_general_topic(chat_id)
|
||||||
"""
|
"""
|
||||||
await self.invoke(
|
await self.invoke(
|
||||||
raw.functions.messages.EditForumTopic(
|
raw.functions.channels.EditForumTopic(
|
||||||
channel=await self.resolve_peer(chat_id),
|
channel=await self.resolve_peer(chat_id),
|
||||||
topic_id=1,
|
topic_id=1,
|
||||||
hidden=True
|
hidden=True
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ class ReopenForumTopic:
|
||||||
await app.reopen_forum_topic(chat_id, topic_id)
|
await app.reopen_forum_topic(chat_id, topic_id)
|
||||||
"""
|
"""
|
||||||
await self.invoke(
|
await self.invoke(
|
||||||
raw.functions.messages.EditForumTopic(
|
raw.functions.channels.EditForumTopic(
|
||||||
channel=await self.resolve_peer(chat_id),
|
channel=await self.resolve_peer(chat_id),
|
||||||
topic_id=topic_id,
|
topic_id=topic_id,
|
||||||
closed=False
|
closed=False
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ class ReopenGeneralTopic:
|
||||||
await app.reopen_general_topic(chat_id, topic_id)
|
await app.reopen_general_topic(chat_id, topic_id)
|
||||||
"""
|
"""
|
||||||
await self.invoke(
|
await self.invoke(
|
||||||
raw.functions.messages.EditForumTopic(
|
raw.functions.channels.EditForumTopic(
|
||||||
channel=await self.resolve_peer(chat_id),
|
channel=await self.resolve_peer(chat_id),
|
||||||
topic_id=1,
|
topic_id=1,
|
||||||
closed=False
|
closed=False
|
||||||
|
|
@ -164,4 +164,5 @@ class SetChatPhoto:
|
||||||
{i.id: i for i in r.users},
|
{i.id: i for i in r.users},
|
||||||
{i.id: i for i in r.chats}
|
{i.id: i for i in r.chats}
|
||||||
)
|
)
|
||||||
return True
|
else:
|
||||||
|
return True
|
||||||
|
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
# Pyrofork - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrofork.
|
|
||||||
#
|
|
||||||
# Pyrofork is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrofork is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from typing import Union
|
|
||||||
import pyrogram
|
|
||||||
from pyrogram import raw, utils
|
|
||||||
|
|
||||||
|
|
||||||
class TransferChatOwnership:
|
|
||||||
async def transfer_chat_ownership(
|
|
||||||
self: "pyrogram.Client",
|
|
||||||
chat_id: Union[int, str],
|
|
||||||
user_id: Union[int, str],
|
|
||||||
password: str,
|
|
||||||
) -> bool:
|
|
||||||
"""Transfer the owner of a chat or channel to another user.
|
|
||||||
|
|
||||||
.. note:
|
|
||||||
|
|
||||||
Requires owner privileges.
|
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
chat_id (``int`` | ``str``):
|
|
||||||
Unique identifier (int) or username (str) of the target chat.
|
|
||||||
Unique identifier for the target chat in form of a *t.me/joinchat/* link, identifier (int) or username
|
|
||||||
of the target channel/supergroup (in the format @username).
|
|
||||||
|
|
||||||
user_id (``int`` | ``str``):
|
|
||||||
Unique identifier (int) or username (str) of the new owner.
|
|
||||||
For a contact that exists in your Telegram address book you can use his phone number (str).
|
|
||||||
|
|
||||||
password (``str``):
|
|
||||||
The 2-step verification password of the current user.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
``bool``: True on success.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: In case of invalid parameters.
|
|
||||||
RPCError: In case of a Telegram RPC error.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
await app.transfer_chat_ownership(chat_id, user_id, "password")
|
|
||||||
"""
|
|
||||||
peer_channel = await self.resolve_peer(chat_id)
|
|
||||||
peer_user = await self.resolve_peer(user_id)
|
|
||||||
|
|
||||||
if not isinstance(peer_channel, raw.types.InputPeerChannel):
|
|
||||||
raise ValueError("The chat_id must belong to a channel/supergroup.")
|
|
||||||
|
|
||||||
if not isinstance(peer_user, raw.types.InputPeerUser):
|
|
||||||
raise ValueError("The user_id must belong to a user.")
|
|
||||||
|
|
||||||
r = await self.invoke(
|
|
||||||
raw.functions.channels.EditCreator(
|
|
||||||
channel=peer_channel,
|
|
||||||
user_id=peer_user,
|
|
||||||
password=utils.compute_password_check(
|
|
||||||
await self.invoke(raw.functions.account.GetPassword()), password
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return bool(r)
|
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -44,7 +44,7 @@ class UnhideGeneralTopic:
|
||||||
await app.unhide_general_topic(chat_id)
|
await app.unhide_general_topic(chat_id)
|
||||||
"""
|
"""
|
||||||
await self.invoke(
|
await self.invoke(
|
||||||
raw.functions.messages.EditForumTopic(
|
raw.functions.channels.EditForumTopic(
|
||||||
channel=await self.resolve_peer(chat_id),
|
channel=await self.resolve_peer(chat_id),
|
||||||
topic_id=1,
|
topic_id=1,
|
||||||
hidden=False
|
hidden=False
|
||||||
|
|
@ -20,7 +20,8 @@
|
||||||
from typing import List, Union
|
from typing import List, Union
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import enums, raw, types, utils
|
from pyrogram import raw
|
||||||
|
from pyrogram import enums
|
||||||
|
|
||||||
|
|
||||||
class UpdateFolder:
|
class UpdateFolder:
|
||||||
|
|
@ -28,7 +29,6 @@ class UpdateFolder:
|
||||||
self: "pyrogram.Client",
|
self: "pyrogram.Client",
|
||||||
folder_id: int,
|
folder_id: int,
|
||||||
title: str,
|
title: str,
|
||||||
title_entities: List["types.MessageEntity"] = None,
|
|
||||||
included_chats: Union[Union[int, str], List[Union[int, str]]] = None,
|
included_chats: Union[Union[int, str], List[Union[int, str]]] = None,
|
||||||
excluded_chats: Union[Union[int, str], List[Union[int, str]]] = None,
|
excluded_chats: Union[Union[int, str], List[Union[int, str]]] = None,
|
||||||
pinned_chats: Union[Union[int, str], List[Union[int, str]]] = None,
|
pinned_chats: Union[Union[int, str], List[Union[int, str]]] = None,
|
||||||
|
|
@ -41,8 +41,7 @@ class UpdateFolder:
|
||||||
exclude_read: bool = None,
|
exclude_read: bool = None,
|
||||||
exclude_archived: bool = None,
|
exclude_archived: bool = None,
|
||||||
color: "enums.FolderColor" = None,
|
color: "enums.FolderColor" = None,
|
||||||
emoji: str = None,
|
emoji: str = None
|
||||||
parse_mode: "pyrogram.enums.ParseMode" = pyrogram.enums.ParseMode.DEFAULT
|
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Create or update a user's folder.
|
"""Create or update a user's folder.
|
||||||
|
|
||||||
|
|
@ -55,9 +54,6 @@ class UpdateFolder:
|
||||||
title (``str``):
|
title (``str``):
|
||||||
Folder title.
|
Folder title.
|
||||||
|
|
||||||
title_entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*):
|
|
||||||
Entities for the folder title.
|
|
||||||
|
|
||||||
included_chats (``int`` | ``str`` | List of ``int`` or ``str``, *optional*):
|
included_chats (``int`` | ``str`` | List of ``int`` or ``str``, *optional*):
|
||||||
Users or chats that should added in the folder
|
Users or chats that should added in the folder
|
||||||
You can pass an ID (int), username (str) or phone number (str).
|
You can pass an ID (int), username (str) or phone number (str).
|
||||||
|
|
@ -102,9 +98,6 @@ class UpdateFolder:
|
||||||
Color type.
|
Color type.
|
||||||
Pass :obj:`~pyrogram.enums.FolderColor` to set folder color.
|
Pass :obj:`~pyrogram.enums.FolderColor` to set folder color.
|
||||||
|
|
||||||
parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*):
|
|
||||||
The parse mode to use for the title.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
``bool``: True, on success.
|
``bool``: True, on success.
|
||||||
|
|
||||||
|
|
@ -114,8 +107,6 @@ class UpdateFolder:
|
||||||
# Create or update folder
|
# Create or update folder
|
||||||
app.update_folder(folder_id, title="New folder", included_chats="me")
|
app.update_folder(folder_id, title="New folder", included_chats="me")
|
||||||
"""
|
"""
|
||||||
title_text, title_entities = (await utils.parse_text_entities(self, title, parse_mode, title_entities)).values()
|
|
||||||
|
|
||||||
if not isinstance(included_chats, list):
|
if not isinstance(included_chats, list):
|
||||||
included_chats = [included_chats] if included_chats else []
|
included_chats = [included_chats] if included_chats else []
|
||||||
if not isinstance(excluded_chats, list):
|
if not isinstance(excluded_chats, list):
|
||||||
|
|
@ -128,10 +119,7 @@ class UpdateFolder:
|
||||||
id=folder_id,
|
id=folder_id,
|
||||||
filter=raw.types.DialogFilter(
|
filter=raw.types.DialogFilter(
|
||||||
id=folder_id,
|
id=folder_id,
|
||||||
title=raw.types.TextWithEntities(
|
title=title,
|
||||||
text=title_text,
|
|
||||||
entities=title_entities or []
|
|
||||||
),
|
|
||||||
pinned_peers=[
|
pinned_peers=[
|
||||||
await self.resolve_peer(user_id)
|
await self.resolve_peer(user_id)
|
||||||
for user_id in pinned_chats
|
for user_id in pinned_chats
|
||||||
|
|
@ -158,4 +146,4 @@ class UpdateFolder:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return bool(r)
|
return r
|
||||||
|
|
|
||||||
|
|
@ -24,33 +24,26 @@ from pyrogram.filters import Filter
|
||||||
|
|
||||||
|
|
||||||
class OnError:
|
class OnError:
|
||||||
def on_error(
|
def on_error(self=None, errors=None) -> Callable:
|
||||||
self=None,
|
|
||||||
errors=None,
|
|
||||||
group: int = 0,
|
|
||||||
) -> Callable:
|
|
||||||
"""Decorator for handling new errors.
|
"""Decorator for handling new errors.
|
||||||
|
|
||||||
This does the same thing as :meth:`~pyrogram.Client.add_handler` using the
|
This does the same thing as :meth:`~pyrogram.Client.add_handler` using the
|
||||||
:obj:`~pyrogram.handlers.ErrorHandler`.
|
:obj:`~pyrogram.handlers.MessageHandler`.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
errors (:obj:`~Exception`, *optional*):
|
errors (:obj:`~Exception`, *optional*):
|
||||||
Pass one or more errors to allow only a subset of errors to be passed
|
Pass one or more errors to allow only a subset of errors to be passed
|
||||||
in your function.
|
in your function.
|
||||||
|
|
||||||
group (``int``, *optional*):
|
|
||||||
The group identifier, defaults to 0.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def decorator(func: Callable) -> Callable:
|
def decorator(func: Callable) -> Callable:
|
||||||
if isinstance(self, pyrogram.Client):
|
if isinstance(self, pyrogram.Client):
|
||||||
self.add_handler(pyrogram.handlers.ErrorHandler(func, errors), group)
|
self.add_handler(pyrogram.handlers.ErrorHandler(func, errors), 0)
|
||||||
elif isinstance(self, Filter) or self is None:
|
elif isinstance(self, Filter) or self is None:
|
||||||
if not hasattr(func, "handlers"):
|
if not hasattr(func, "handlers"):
|
||||||
func.handlers = []
|
func.handlers = []
|
||||||
|
|
||||||
func.handlers.append((pyrogram.handlers.ErrorHandler(func, self), group))
|
func.handlers.append((pyrogram.handlers.ErrorHandler(func, self), 0))
|
||||||
|
|
||||||
return func
|
return func
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from typing import Callable
|
from typing import Callable, Optional, Union
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram.filters import Filter
|
from pyrogram.filters import Filter
|
||||||
|
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
# Pyrofork - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrofork.
|
|
||||||
#
|
|
||||||
# Pyrofork is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrofork is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from .create_forum_topic import CreateForumTopic
|
|
||||||
from .close_forum_topic import CloseForumTopic
|
|
||||||
from .close_general_topic import CloseGeneralTopic
|
|
||||||
from .delete_forum_topic import DeleteForumTopic
|
|
||||||
from .edit_forum_topic import EditForumTopic
|
|
||||||
from .edit_general_topic import EditGeneralTopic
|
|
||||||
from .reopen_forum_topic import ReopenForumTopic
|
|
||||||
from .reopen_general_topic import ReopenGeneralTopic
|
|
||||||
from .hide_general_topic import HideGeneralTopic
|
|
||||||
from .unhide_general_topic import UnhideGeneralTopic
|
|
||||||
from .get_forum_topics import GetForumTopics
|
|
||||||
from .get_forum_topics_by_id import GetForumTopicsByID
|
|
||||||
from .get_forum_topics_count import GetForumTopicsCount
|
|
||||||
|
|
||||||
|
|
||||||
class Forums(
|
|
||||||
GetForumTopics,
|
|
||||||
GetForumTopicsByID,
|
|
||||||
GetForumTopicsCount,
|
|
||||||
CreateForumTopic,
|
|
||||||
CloseForumTopic,
|
|
||||||
CloseGeneralTopic,
|
|
||||||
DeleteForumTopic,
|
|
||||||
EditForumTopic,
|
|
||||||
EditGeneralTopic,
|
|
||||||
ReopenForumTopic,
|
|
||||||
ReopenGeneralTopic,
|
|
||||||
HideGeneralTopic,
|
|
||||||
UnhideGeneralTopic,
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
# Pyrofork - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrofork.
|
|
||||||
#
|
|
||||||
# Pyrofork is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrofork is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import logging
|
|
||||||
from typing import Union, Optional, AsyncGenerator
|
|
||||||
|
|
||||||
import pyrogram
|
|
||||||
from pyrogram import raw
|
|
||||||
from pyrogram import types
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
async def get_chunk(
|
|
||||||
client: "pyrogram.Client",
|
|
||||||
chat_id: Union[int, str],
|
|
||||||
offset_date: int,
|
|
||||||
offset_id: int,
|
|
||||||
offset_topic: int,
|
|
||||||
limit: int
|
|
||||||
):
|
|
||||||
peer = await client.resolve_peer(chat_id)
|
|
||||||
|
|
||||||
r = await client.invoke(
|
|
||||||
raw.functions.messages.GetForumTopics(
|
|
||||||
channel=peer,
|
|
||||||
offset_date=offset_date,
|
|
||||||
offset_id=offset_id,
|
|
||||||
offset_topic=offset_topic,
|
|
||||||
limit=limit
|
|
||||||
),
|
|
||||||
sleep_threshold=-1
|
|
||||||
)
|
|
||||||
|
|
||||||
return r.topics
|
|
||||||
|
|
||||||
|
|
||||||
class GetForumTopics:
|
|
||||||
async def get_forum_topics(
|
|
||||||
self: "pyrogram.Client",
|
|
||||||
chat_id: Union[int, str],
|
|
||||||
limit: int = 0
|
|
||||||
) -> Optional[AsyncGenerator["types.ForumTopic", None]]:
|
|
||||||
"""Get forum topics from a chat.
|
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
chat_id (``int`` | ``str``):
|
|
||||||
Unique identifier (int) or username (str) of the target chat.
|
|
||||||
You can also use chat public link in form of *t.me/<username>* (str).
|
|
||||||
|
|
||||||
limit (``int``, *optional*):
|
|
||||||
Limits the number of topics to be retrieved.
|
|
||||||
By default, no limit is applied and all topics are returned.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
``Generator``: On success, a generator yielding :obj:`~pyrogram.types.ForumTopic` objects is returned.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# get all forum topics
|
|
||||||
async for topic in app.get_forum_topics(chat_id):
|
|
||||||
print(topic)
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: In case of invalid arguments.
|
|
||||||
"""
|
|
||||||
current = 0
|
|
||||||
offset_date = 0
|
|
||||||
offset_id = 0
|
|
||||||
offset_topic = 0
|
|
||||||
total = abs(limit) or (1 << 31) - 1
|
|
||||||
chunk_limit = min(100, total)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
topics = await get_chunk(
|
|
||||||
client=self,
|
|
||||||
chat_id=chat_id,
|
|
||||||
offset_date=offset_date,
|
|
||||||
offset_id=offset_id,
|
|
||||||
offset_topic=offset_topic,
|
|
||||||
limit=chunk_limit
|
|
||||||
)
|
|
||||||
|
|
||||||
if not topics:
|
|
||||||
return
|
|
||||||
|
|
||||||
last_topic = topics[-1]
|
|
||||||
offset_date = int(last_topic.date) if last_topic.date else 0
|
|
||||||
offset_id = last_topic.top_message if last_topic.top_message else 0
|
|
||||||
offset_topic = last_topic.id
|
|
||||||
|
|
||||||
for topic in topics:
|
|
||||||
yield types.ForumTopic._parse(topic)
|
|
||||||
|
|
||||||
current += 1
|
|
||||||
|
|
||||||
if current >= total:
|
|
||||||
return
|
|
||||||
|
|
@ -17,10 +17,8 @@
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from .add_task_to_todo import AddTaskToTodo
|
|
||||||
from .copy_media_group import CopyMediaGroup
|
from .copy_media_group import CopyMediaGroup
|
||||||
from .copy_message import CopyMessage
|
from .copy_message import CopyMessage
|
||||||
from .delete_chat_history import DeleteChatHistory
|
|
||||||
from .delete_messages import DeleteMessages
|
from .delete_messages import DeleteMessages
|
||||||
from .delete_scheduled_messages import DeleteScheduledMessages
|
from .delete_scheduled_messages import DeleteScheduledMessages
|
||||||
from .download_media import DownloadMedia
|
from .download_media import DownloadMedia
|
||||||
|
|
@ -53,7 +51,6 @@ from .search_global_hashtag_messages import SearchGlobalHashtagMessages
|
||||||
from .search_global_hashtag_messages_count import SearchGlobalHashtagMessagesCount
|
from .search_global_hashtag_messages_count import SearchGlobalHashtagMessagesCount
|
||||||
from .search_messages import SearchMessages
|
from .search_messages import SearchMessages
|
||||||
from .search_messages_count import SearchMessagesCount
|
from .search_messages_count import SearchMessagesCount
|
||||||
from .set_todo_tasks_completion import SetTodoTasksCompletion
|
|
||||||
from .send_animation import SendAnimation
|
from .send_animation import SendAnimation
|
||||||
from .send_audio import SendAudio
|
from .send_audio import SendAudio
|
||||||
from .send_cached_media import SendCachedMedia
|
from .send_cached_media import SendCachedMedia
|
||||||
|
|
@ -68,7 +65,6 @@ from .send_photo import SendPhoto
|
||||||
from .send_poll import SendPoll
|
from .send_poll import SendPoll
|
||||||
from .send_reaction import SendReaction
|
from .send_reaction import SendReaction
|
||||||
from .send_sticker import SendSticker
|
from .send_sticker import SendSticker
|
||||||
from .send_todo import SendTodo
|
|
||||||
from .send_venue import SendVenue
|
from .send_venue import SendVenue
|
||||||
from .send_video import SendVideo
|
from .send_video import SendVideo
|
||||||
from .send_video_note import SendVideoNote
|
from .send_video_note import SendVideoNote
|
||||||
|
|
@ -78,12 +74,9 @@ from .start_bot import StartBot
|
||||||
from .stop_poll import StopPoll
|
from .stop_poll import StopPoll
|
||||||
from .stream_media import StreamMedia
|
from .stream_media import StreamMedia
|
||||||
from .vote_poll import VotePoll
|
from .vote_poll import VotePoll
|
||||||
from .transcribe_audio import TranscribeAudio
|
|
||||||
from .translate_text import TranslateText
|
from .translate_text import TranslateText
|
||||||
|
|
||||||
class Messages(
|
class Messages(
|
||||||
AddTaskToTodo,
|
|
||||||
DeleteChatHistory,
|
|
||||||
DeleteMessages,
|
DeleteMessages,
|
||||||
DeleteScheduledMessages,
|
DeleteScheduledMessages,
|
||||||
EditMessageCaption,
|
EditMessageCaption,
|
||||||
|
|
@ -97,7 +90,6 @@ class Messages(
|
||||||
GetMessages,
|
GetMessages,
|
||||||
GetMessageReadParticipants,
|
GetMessageReadParticipants,
|
||||||
GetScheduledMessages,
|
GetScheduledMessages,
|
||||||
SetTodoTasksCompletion,
|
|
||||||
SendAudio,
|
SendAudio,
|
||||||
SendChatAction,
|
SendChatAction,
|
||||||
SendContact,
|
SendContact,
|
||||||
|
|
@ -108,7 +100,6 @@ class Messages(
|
||||||
SendMessage,
|
SendMessage,
|
||||||
SendPhoto,
|
SendPhoto,
|
||||||
SendSticker,
|
SendSticker,
|
||||||
SendTodo,
|
|
||||||
SendVenue,
|
SendVenue,
|
||||||
SendVideo,
|
SendVideo,
|
||||||
SendVideoNote,
|
SendVideoNote,
|
||||||
|
|
@ -142,7 +133,6 @@ class Messages(
|
||||||
GetDiscussionRepliesCount,
|
GetDiscussionRepliesCount,
|
||||||
StreamMedia,
|
StreamMedia,
|
||||||
GetCustomEmojiStickers,
|
GetCustomEmojiStickers,
|
||||||
TranscribeAudio,
|
|
||||||
TranslateText,
|
TranslateText,
|
||||||
StartBot
|
StartBot
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
# Pyrofork - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrofork.
|
|
||||||
#
|
|
||||||
# Pyrofork is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrofork is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import pyrogram
|
|
||||||
|
|
||||||
from pyrogram import raw, types, utils
|
|
||||||
from typing import Union, List
|
|
||||||
|
|
||||||
|
|
||||||
class AddTaskToTodo:
|
|
||||||
async def add_task_to_todo(
|
|
||||||
self: "pyrogram.Client",
|
|
||||||
chat_id: Union[int, str],
|
|
||||||
message_id: Union[int, str],
|
|
||||||
tasks: List["types.InputTodoTask"],
|
|
||||||
parse_mode: str = None
|
|
||||||
) -> "types.Message":
|
|
||||||
"""Add tasks to a todo list.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
chat_id (``int`` | ``str``):
|
|
||||||
Unique identifier for the target chat or username of the target channel.
|
|
||||||
|
|
||||||
message_id (``int`` | ``str``):
|
|
||||||
Unique identifier for the target message or username of the target channel.
|
|
||||||
|
|
||||||
tasks (List of :obj:`~pyrogram.types.InputTodoTask`):
|
|
||||||
List of tasks to be added to the todo list.
|
|
||||||
|
|
||||||
parse_mode (``str``, *optional*):
|
|
||||||
The parse mode to use for formatting the text.
|
|
||||||
|
|
||||||
entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*):
|
|
||||||
Entities in the title of the todo list.
|
|
||||||
"""
|
|
||||||
tasks_list = []
|
|
||||||
get_message = await self.get_messages(chat_id, message_id)
|
|
||||||
if not isinstance(get_message, types.Message):
|
|
||||||
raise ValueError("The message must be a valid Message object.")
|
|
||||||
todo_list = get_message.todo
|
|
||||||
last_task_id = max((task.id for task in todo_list.tasks), default=0)
|
|
||||||
for i, task in enumerate(tasks):
|
|
||||||
task_title, task_entities = (await utils.parse_text_entities(self, task.title, parse_mode, task.entities)).values()
|
|
||||||
tasks_list.append(
|
|
||||||
raw.types.TodoItem(
|
|
||||||
id=last_task_id + i + 1,
|
|
||||||
title=raw.types.TextWithEntities(
|
|
||||||
text=task_title,
|
|
||||||
entities=task_entities or []
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
r = await self.invoke(
|
|
||||||
raw.functions.messages.AppendTodoList(
|
|
||||||
peer=await self.resolve_peer(chat_id),
|
|
||||||
msg_id=message_id,
|
|
||||||
list=tasks_list
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for update in r.updates:
|
|
||||||
if isinstance(update, (raw.types.UpdateNewMessage,
|
|
||||||
raw.types.UpdateNewChannelMessage,
|
|
||||||
raw.types.UpdateNewScheduledMessage,
|
|
||||||
raw.types.UpdateBotNewBusinessMessage)):
|
|
||||||
return types.Message._parse(self, update.message, update, r.users, r.chats)
|
|
||||||
|
|
@ -34,7 +34,6 @@ class CopyMediaGroup:
|
||||||
has_spoilers: Union[List[bool], bool] = None,
|
has_spoilers: Union[List[bool], bool] = None,
|
||||||
disable_notification: bool = None,
|
disable_notification: bool = None,
|
||||||
message_thread_id: int = None,
|
message_thread_id: int = None,
|
||||||
send_as: Union[int, str] = None,
|
|
||||||
reply_to_message_id: int = None,
|
reply_to_message_id: int = None,
|
||||||
reply_to_chat_id: Union[int, str] = None,
|
reply_to_chat_id: Union[int, str] = None,
|
||||||
reply_to_story_id: int = None,
|
reply_to_story_id: int = None,
|
||||||
|
|
@ -45,8 +44,6 @@ class CopyMediaGroup:
|
||||||
schedule_date: datetime = None,
|
schedule_date: datetime = None,
|
||||||
invert_media: bool = None,
|
invert_media: bool = None,
|
||||||
protect_content: bool = None,
|
protect_content: bool = None,
|
||||||
allow_paid_broadcast: bool = None,
|
|
||||||
message_effect_id: int = None,
|
|
||||||
) -> List["types.Message"]:
|
) -> List["types.Message"]:
|
||||||
"""Copy a media group by providing one of the message ids.
|
"""Copy a media group by providing one of the message ids.
|
||||||
|
|
||||||
|
|
@ -76,9 +73,6 @@ class CopyMediaGroup:
|
||||||
If a ``string`` is passed, it becomes a caption only for the first media.
|
If a ``string`` is passed, it becomes a caption only for the first media.
|
||||||
If a list of ``string`` passed, each element becomes caption for each media element.
|
If a list of ``string`` passed, each element becomes caption for each media element.
|
||||||
You can pass ``None`` in list to keep the original caption (see examples below).
|
You can pass ``None`` in list to keep the original caption (see examples below).
|
||||||
|
|
||||||
has_spoilers (``bool``, *optional*):
|
|
||||||
Pass True if the photo needs to be covered with a spoiler animation.
|
|
||||||
|
|
||||||
disable_notification (``bool``, *optional*):
|
disable_notification (``bool``, *optional*):
|
||||||
Sends the message silently.
|
Sends the message silently.
|
||||||
|
|
@ -88,10 +82,6 @@ class CopyMediaGroup:
|
||||||
Unique identifier for the target message thread (topic) of the forum.
|
Unique identifier for the target message thread (topic) of the forum.
|
||||||
For supergroups only.
|
For supergroups only.
|
||||||
|
|
||||||
send_as (``int`` | ``str``):
|
|
||||||
Unique identifier (int) or username (str) of the chat or channel to send the message as.
|
|
||||||
You can use this to send the message on behalf of a chat or channel where you have appropriate permissions.
|
|
||||||
|
|
||||||
reply_to_message_id (``int``, *optional*):
|
reply_to_message_id (``int``, *optional*):
|
||||||
If the message is a reply, ID of the original message.
|
If the message is a reply, ID of the original message.
|
||||||
|
|
||||||
|
|
@ -123,12 +113,6 @@ class CopyMediaGroup:
|
||||||
protect_content (``bool``, *optional*):
|
protect_content (``bool``, *optional*):
|
||||||
Protects the contents of the sent message from forwarding and saving
|
Protects the contents of the sent message from forwarding and saving
|
||||||
|
|
||||||
allow_paid_broadcast (``bool``, *optional*):
|
|
||||||
Pass True to allow the message to ignore regular broadcast limits for a small fee; for bots only
|
|
||||||
|
|
||||||
message_effect_id (``int`` ``64-bit``, *optional*):
|
|
||||||
Unique identifier of the message effect to be added to the message; for private chats only.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of :obj:`~pyrogram.types.Message`: On success, a list of copied messages is returned.
|
List of :obj:`~pyrogram.types.Message`: On success, a list of copied messages is returned.
|
||||||
|
|
||||||
|
|
@ -180,38 +164,28 @@ class CopyMediaGroup:
|
||||||
**await self.parser.parse(
|
**await self.parser.parse(
|
||||||
captions[i] if isinstance(captions, list) and i < len(captions) and captions[i] else
|
captions[i] if isinstance(captions, list) and i < len(captions) and captions[i] else
|
||||||
captions if isinstance(captions, str) and i == 0 else
|
captions if isinstance(captions, str) and i == 0 else
|
||||||
message.caption if (
|
message.caption if message.caption and message.caption != "None" and not type(
|
||||||
message.caption
|
captions) is str else "")
|
||||||
and message.caption != "None"
|
|
||||||
and not isinstance(captions, str)
|
|
||||||
) else ""
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
reply_to = await utils.get_reply_to(
|
|
||||||
client=self,
|
|
||||||
reply_to_message_id=reply_to_message_id,
|
|
||||||
message_thread_id=message_thread_id,
|
|
||||||
reply_to_chat_id=reply_to_chat_id,
|
|
||||||
reply_to_story_id=reply_to_story_id,
|
|
||||||
quote_text=quote_text,
|
|
||||||
quote_entities=quote_entities,
|
|
||||||
quote_offset=quote_offset,
|
|
||||||
)
|
|
||||||
|
|
||||||
r = await self.invoke(
|
r = await self.invoke(
|
||||||
raw.functions.messages.SendMultiMedia(
|
raw.functions.messages.SendMultiMedia(
|
||||||
peer=await self.resolve_peer(chat_id),
|
peer=await self.resolve_peer(chat_id),
|
||||||
multi_media=multi_media,
|
multi_media=multi_media,
|
||||||
silent=disable_notification or None,
|
silent=disable_notification or None,
|
||||||
reply_to=reply_to,
|
reply_to=utils.get_reply_to(
|
||||||
send_as=await self.resolve_peer(send_as) if send_as else None,
|
reply_to_message_id=reply_to_message_id,
|
||||||
|
message_thread_id=message_thread_id,
|
||||||
|
reply_to_peer=await self.resolve_peer(reply_to_chat_id) if reply_to_chat_id else None,
|
||||||
|
reply_to_story_id=reply_to_story_id,
|
||||||
|
quote_text=quote_text,
|
||||||
|
quote_entities=quote_entities,
|
||||||
|
quote_offset=quote_offset,
|
||||||
|
),
|
||||||
schedule_date=utils.datetime_to_timestamp(schedule_date),
|
schedule_date=utils.datetime_to_timestamp(schedule_date),
|
||||||
noforwards=protect_content,
|
noforwards=protect_content,
|
||||||
invert_media=invert_media,
|
invert_media=invert_media
|
||||||
allow_paid_floodskip=allow_paid_broadcast,
|
|
||||||
effect=message_effect_id,
|
|
||||||
),
|
),
|
||||||
sleep_threshold=60
|
sleep_threshold=60
|
||||||
)
|
)
|
||||||
|
|
@ -228,4 +202,4 @@ class CopyMediaGroup:
|
||||||
users=r.users,
|
users=r.users,
|
||||||
chats=r.chats
|
chats=r.chats
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
# Pyrofork - Telegram MTProto API Client Library for Python
|
|
||||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
|
||||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
|
||||||
#
|
|
||||||
# This file is part of Pyrofork.
|
|
||||||
#
|
|
||||||
# Pyrofork is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Lesser General Public License as published
|
|
||||||
# by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# Pyrofork is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
|
||||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
import logging
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
import pyrogram
|
|
||||||
from pyrogram import raw
|
|
||||||
from pyrogram import utils
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class DeleteChatHistory:
|
|
||||||
async def delete_chat_history(
|
|
||||||
self: "pyrogram.Client",
|
|
||||||
chat_id: Union[int, str],
|
|
||||||
max_id: int = 0,
|
|
||||||
revoke: bool = None,
|
|
||||||
just_clear = None,
|
|
||||||
min_date: datetime = None,
|
|
||||||
max_date: datetime = None,
|
|
||||||
) -> int:
|
|
||||||
"""Delete the history of a chat.
|
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
chat_id (``int`` | ``str``):
|
|
||||||
Unique identifier (int) or username (str) of the target chat.
|
|
||||||
|
|
||||||
max_id (``int``, *optional*):
|
|
||||||
Maximum ID of message to delete.
|
|
||||||
|
|
||||||
revoke (``bool``, *optional*):
|
|
||||||
Deletes messages history for everyone.
|
|
||||||
Required ``True`` if using in channel.
|
|
||||||
|
|
||||||
just_clear (``bool``, *optional*):
|
|
||||||
If True, clear history for the current user, without actually removing chat.
|
|
||||||
For private and simple group chats only.
|
|
||||||
|
|
||||||
min_date (:py:obj:`~datetime.datetime`, *optional*):
|
|
||||||
Delete all messages newer than this time.
|
|
||||||
For private and simple group chats only.
|
|
||||||
|
|
||||||
max_date (:py:obj:`~datetime.datetime`, *optional*):
|
|
||||||
Delete all messages older than this time.
|
|
||||||
For private and simple group chats only.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
``int``: Amount of affected messages
|
|
||||||
|
|
||||||
Example:
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Delete all messages in channel
|
|
||||||
await app.delete_chat_history(chat_id, revoke=True)
|
|
||||||
"""
|
|
||||||
peer = await self.resolve_peer(chat_id)
|
|
||||||
|
|
||||||
if isinstance(peer, raw.types.InputPeerChannel):
|
|
||||||
r = await self.invoke(
|
|
||||||
raw.functions.channels.DeleteHistory(
|
|
||||||
channel=raw.types.InputChannel(
|
|
||||||
channel_id=peer.channel_id,
|
|
||||||
access_hash=peer.access_hash
|
|
||||||
),
|
|
||||||
max_id=max_id,
|
|
||||||
for_everyone=revoke
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
r = await self.invoke(
|
|
||||||
raw.functions.messages.DeleteHistory(
|
|
||||||
peer=peer,
|
|
||||||
max_id=max_id,
|
|
||||||
just_clear=just_clear,
|
|
||||||
revoke=revoke,
|
|
||||||
min_date=utils.datetime_to_timestamp(min_date),
|
|
||||||
max_date=utils.datetime_to_timestamp(max_date)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
return len(r.updates[0].messages) if isinstance(peer, raw.types.InputPeerChannel) else r.pts_count
|
|
||||||
|
|
@ -150,17 +150,6 @@ class DownloadMedia:
|
||||||
directory, file_name = os.path.split(file_name)
|
directory, file_name = os.path.split(file_name)
|
||||||
file_name = file_name or media_file_name or ""
|
file_name = file_name or media_file_name or ""
|
||||||
|
|
||||||
# Sanitize file name
|
|
||||||
# CWE-22: Path Traversal
|
|
||||||
if file_name:
|
|
||||||
# Remove any path components, keeping only the basename
|
|
||||||
file_name = os.path.basename(file_name)
|
|
||||||
# Remove null bytes which could cause issues
|
|
||||||
file_name = file_name.replace('\x00', '')
|
|
||||||
# Handle edge cases
|
|
||||||
if not file_name or file_name in ('.', '..'):
|
|
||||||
file_name = ""
|
|
||||||
|
|
||||||
if not os.path.isabs(file_name):
|
if not os.path.isabs(file_name):
|
||||||
directory = self.PARENT_DIR / (directory or DEFAULT_DOWNLOAD_DIR)
|
directory = self.PARENT_DIR / (directory or DEFAULT_DOWNLOAD_DIR)
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue