diff options
author | halcy <halcy@ARARAGI-KUN> | 2022-11-27 02:43:22 +0200 |
---|---|---|
committer | halcy <halcy@ARARAGI-KUN> | 2022-11-27 02:43:22 +0200 |
commit | 5cf0fa27a95f8c56280ea429dd1d57529fc490ee (patch) | |
tree | 26e4485d4e69052bc53c151ba807b8260185a419 /mastodon | |
parent | 7331f7774ae10d927e086318338989de6bc37cad (diff) | |
download | mastodon.py-5cf0fa27a95f8c56280ea429dd1d57529fc490ee.tar.gz |
add admin stats APIs
Diffstat (limited to 'mastodon')
-rw-r--r-- | mastodon/Mastodon.py | 139 |
1 files changed, 135 insertions, 4 deletions
diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py index 82e058c..03aa413 100644 --- a/mastodon/Mastodon.py +++ b/mastodon/Mastodon.py | |||
@@ -108,7 +108,6 @@ def api_version(created_ver, last_changed_ver, return_value_ver): | |||
108 | raise MastodonVersionError( | 108 | raise MastodonVersionError( |
109 | "Version check failed (Need version " + version + ")") | 109 | "Version check failed (Need version " + version + ")") |
110 | elif major == self.mastodon_major and minor > self.mastodon_minor: | 110 | elif major == self.mastodon_major and minor > self.mastodon_minor: |
111 | print(self.mastodon_minor) | ||
112 | raise MastodonVersionError( | 111 | raise MastodonVersionError( |
113 | "Version check failed (Need version " + version + ")") | 112 | "Version check failed (Need version " + version + ")") |
114 | elif major == self.mastodon_major and minor == self.mastodon_minor and patch > self.mastodon_patch: | 113 | elif major == self.mastodon_major and minor == self.mastodon_minor and patch > self.mastodon_patch: |
@@ -264,6 +263,9 @@ class Mastodon: | |||
264 | __DICT_VERSION_ANNOUNCEMENT = bigger_version("3.1.0", __DICT_VERSION_REACTION) | 263 | __DICT_VERSION_ANNOUNCEMENT = bigger_version("3.1.0", __DICT_VERSION_REACTION) |
265 | __DICT_VERSION_STATUS_EDIT = "3.5.0" | 264 | __DICT_VERSION_STATUS_EDIT = "3.5.0" |
266 | __DICT_VERSION_ADMIN_DOMAIN_BLOCK = "4.0.0" | 265 | __DICT_VERSION_ADMIN_DOMAIN_BLOCK = "4.0.0" |
266 | __DICT_VERSION_ADMIN_MEASURE = "3.5.0" | ||
267 | __DICT_VERSION_ADMIN_DIMENSION = "3.5.0" | ||
268 | __DICT_VERSION_ADMIN_RETENTION = "3.5.0" | ||
267 | 269 | ||
268 | ### | 270 | ### |
269 | # Registering apps | 271 | # Registering apps |
@@ -432,7 +434,6 @@ class Mastodon: | |||
432 | try_base_url = secret_file.readline().rstrip() | 434 | try_base_url = secret_file.readline().rstrip() |
433 | if try_base_url is not None and len(try_base_url) != 0: | 435 | if try_base_url is not None and len(try_base_url) != 0: |
434 | try_base_url = Mastodon.__protocolize(try_base_url) | 436 | try_base_url = Mastodon.__protocolize(try_base_url) |
435 | print(self.api_base_url, try_base_url) | ||
436 | if not (self.api_base_url is None or try_base_url == self.api_base_url): | 437 | if not (self.api_base_url is None or try_base_url == self.api_base_url): |
437 | raise MastodonIllegalArgumentError('Mismatch in base URLs between files and/or specified') | 438 | raise MastodonIllegalArgumentError('Mismatch in base URLs between files and/or specified') |
438 | self.api_base_url = try_base_url | 439 | self.api_base_url = try_base_url |
@@ -544,7 +545,6 @@ class Mastodon: | |||
544 | We parse this from the hopefully present "Date" header, but make no effort to compensate for latency. | 545 | We parse this from the hopefully present "Date" header, but make no effort to compensate for latency. |
545 | """ | 546 | """ |
546 | response = self.__api_request("HEAD", "/", return_response_object=True) | 547 | response = self.__api_request("HEAD", "/", return_response_object=True) |
547 | print(response.headers) | ||
548 | if 'Date' in response.headers: | 548 | if 'Date' in response.headers: |
549 | server_time_datetime = dateutil.parser.parse(response.headers['Date']) | 549 | server_time_datetime = dateutil.parser.parse(response.headers['Date']) |
550 | 550 | ||
@@ -3456,6 +3456,130 @@ class Mastodon: | |||
3456 | else: | 3456 | else: |
3457 | raise AttributeError("You must provide an id of an existing domain block to remove it.") | 3457 | raise AttributeError("You must provide an id of an existing domain block to remove it.") |
3458 | 3458 | ||
3459 | @api_version("3.5.0", "3.5.0", __DICT_VERSION_ADMIN_MEASURE) | ||
3460 | def admin_measures(self, start_at, end_at, active_users=False, new_users=False, interactions=False, opened_reports = False, resolved_reports=False, | ||
3461 | tag_accounts=None, tag_uses=None, tag_servers=None, instance_accounts=None, instance_media_attachments=None, instance_reports=None, | ||
3462 | instance_statuses=None, instance_follows=None, instance_followers=None): | ||
3463 | """ | ||
3464 | Retrieves numerical instance information for the time period (at day granularity) between `start_at` and `end_at`. | ||
3465 | |||
3466 | * `active_users`: Pass true to retrieve the number of active users on your instance within the time period | ||
3467 | * `new_users`: Pass true to retrieve the number of users who joined your instance within the time period | ||
3468 | * `interactions`: Pass true to retrieve the number of interactions (favourites, boosts, replies) on local statuses within the time period | ||
3469 | * `opened_reports`: Pass true to retrieve the number of reports filed within the time period | ||
3470 | * `resolved_reports` = Pass true to retrieve the number of reports resolved within the time period | ||
3471 | * `tag_accounts`: Pass a tag ID to get the number of accounts which used that tag in at least one status within the time period | ||
3472 | * `tag_uses`: Pass a tag ID to get the number of statuses which used that tag within the time period | ||
3473 | * `tag_servers`: Pass a tag ID to to get the number of remote origin servers for statuses which used that tag within the time period | ||
3474 | * `instance_accounts`: Pass a domain to get the number of accounts originating from that remote domain within the time period | ||
3475 | * `instance_media_attachments`: Pass a domain to get the amount of space used by media attachments from that remote domain within the time period | ||
3476 | * `instance_reports`: Pass a domain to get the number of reports filed against accounts from that remote domain within the time period | ||
3477 | * `instance_statuses`: Pass a domain to get the number of statuses originating from that remote domain within the time period | ||
3478 | * `instance_follows`: Pass a domain to get the number of accounts from a remote domain followed by that local user within the time period | ||
3479 | * `instance_followers`: Pass a domain to get the number of local accounts followed by accounts from that remote domain within the time period | ||
3480 | |||
3481 | This API call is relatively expensive - watch your servers load if you want to get a lot of statistical data. Especially the instance_statuses stats | ||
3482 | might take a long time to compute and, in fact, time out. | ||
3483 | |||
3484 | There is currently no way to get tag IDs implemented in Mastodon.py, because the Mastodon public API does not implement one. This will be fixed in a future | ||
3485 | release. | ||
3486 | |||
3487 | Returns a list of `admin measure dicts`_. | ||
3488 | """ | ||
3489 | params_init = locals() | ||
3490 | keys = [] | ||
3491 | for key in ["active_users", "new_users", "interactions", "opened_reports", "resolved_reports"]: | ||
3492 | if params_init[key] == True: | ||
3493 | keys.append(key) | ||
3494 | |||
3495 | params = {} | ||
3496 | for key in ["tag_accounts", "tag_uses", "tag_servers"]: | ||
3497 | if params_init[key] is not None: | ||
3498 | keys.append(key) | ||
3499 | params[key] = {"id": self.__unpack_id(params_init[key])} | ||
3500 | for key in ["instance_accounts", "instance_media_attachments", "instance_reports", "instance_statuses", "instance_follows", "instance_followers"]: | ||
3501 | if params_init[key] is not None: | ||
3502 | keys.append(key) | ||
3503 | params[key] = {"domain": Mastodon.__deprotocolize(params_init[key]).split("/")[0]} | ||
3504 | |||
3505 | if len(keys) == 0: | ||
3506 | raise MastodonIllegalArgumentError("Must request at least one metric.") | ||
3507 | |||
3508 | params["keys"] = keys | ||
3509 | params["start_at"] = self.__consistent_isoformat_utc(start_at) | ||
3510 | params["end_at"] = self.__consistent_isoformat_utc(end_at) | ||
3511 | |||
3512 | return self.__api_request('POST', '/api/v1/admin/measures', params, use_json=True) | ||
3513 | |||
3514 | @api_version("3.5.0", "3.5.0", __DICT_VERSION_ADMIN_DIMENSION) | ||
3515 | def admin_dimensions(self, start_at, end_at, limit=None, languages=False, sources=False, servers=False, space_usage=False, software_versions=False, | ||
3516 | tag_servers=None, tag_languages=None, instance_accounts=None, instance_languages=None): | ||
3517 | """ | ||
3518 | Retrieves primarily categorical instance information for the time period (at day granularity) between `start_at` and `end_at`. | ||
3519 | |||
3520 | * `languages`: Pass true to get the most-used languages on this server | ||
3521 | * `sources`: Pass true to get the most-used client apps on this server | ||
3522 | * `servers`: Pass true to get the remote servers with the most statuses | ||
3523 | * `space_usage`: Pass true to get the how much space is used by different components your software stack | ||
3524 | * `software_versions`: Pass true to get the version numbers for your software stack | ||
3525 | * `tag_servers`: Pass a tag ID to get the most-common servers for statuses including a trending tag | ||
3526 | * `tag_languages`: Pass a tag ID to get the most-used languages for statuses including a trending tag | ||
3527 | * `instance_accounts`: Pass a domain to get the most-followed accounts from a remote server | ||
3528 | * `instance_languages`: Pass a domain to get the most-used languages from a remote server | ||
3529 | |||
3530 | Pass `limit` to set how many results you want on queries where that makes sense. | ||
3531 | |||
3532 | This API call is relatively expensive - watch your servers load if you want to get a lot of statistical data. | ||
3533 | |||
3534 | There is currently no way to get tag IDs implemented in Mastodon.py, because the Mastodon public API does not implement one. This will be fixed in a future | ||
3535 | release. | ||
3536 | |||
3537 | Returns a list of `admin dimensions dicts`_. | ||
3538 | """ | ||
3539 | params_init = locals() | ||
3540 | keys = [] | ||
3541 | for key in ["languages", "sources", "servers", "space_usage", "software_versions"]: | ||
3542 | if params_init[key] == True: | ||
3543 | keys.append(key) | ||
3544 | |||
3545 | params = {} | ||
3546 | for key in ["tag_servers", "tag_languages"]: | ||
3547 | if params_init[key] is not None: | ||
3548 | keys.append(key) | ||
3549 | params[key] = {"id": self.__unpack_id(params_init[key])} | ||
3550 | for key in ["instance_accounts", "instance_languages"]: | ||
3551 | if params_init[key] is not None: | ||
3552 | keys.append(key) | ||
3553 | params[key] = {"domain": Mastodon.__deprotocolize(params_init[key]).split("/")[0]} | ||
3554 | |||
3555 | if len(keys) == 0: | ||
3556 | raise MastodonIllegalArgumentError("Must request at least one dimension.") | ||
3557 | |||
3558 | params["keys"] = keys | ||
3559 | if limit is not None: | ||
3560 | params["limit"] = limit | ||
3561 | params["start_at"] = self.__consistent_isoformat_utc(start_at) | ||
3562 | params["end_at"] = self.__consistent_isoformat_utc(end_at) | ||
3563 | |||
3564 | return self.__api_request('POST', '/api/v1/admin/dimensions', params, use_json=True) | ||
3565 | |||
3566 | @api_version("3.5.0", "3.5.0", __DICT_VERSION_ADMIN_RETENTION) | ||
3567 | def admin_retention(self, start_at, end_at, frequency="day"): | ||
3568 | """ | ||
3569 | Gets user retention statistics (at `frequency` - "day" or "month" - granularity) between `start_at` and `end_at`. | ||
3570 | |||
3571 | Returns a list of `admin retention dicts`_ | ||
3572 | """ | ||
3573 | if not frequency in ["day", "month"]: | ||
3574 | raise MastodonIllegalArgumentError("Frequency must be day or month") | ||
3575 | |||
3576 | params = { | ||
3577 | "start_at": self.__consistent_isoformat_utc(start_at), | ||
3578 | "end_at": self.__consistent_isoformat_utc(end_at), | ||
3579 | "frequency": frequency | ||
3580 | } | ||
3581 | return self.__api_request('POST', '/api/v1/admin/retention', params) | ||
3582 | |||
3459 | ### | 3583 | ### |
3460 | # Push subscription crypto utilities | 3584 | # Push subscription crypto utilities |
3461 | ### | 3585 | ### |
@@ -3942,7 +4066,6 @@ class Mastodon: | |||
3942 | if not response_object.ok: | 4066 | if not response_object.ok: |
3943 | try: | 4067 | try: |
3944 | response = response_object.json(object_hook=self.__json_hooks) | 4068 | response = response_object.json(object_hook=self.__json_hooks) |
3945 | print(response) | ||
3946 | if isinstance(response, dict) and 'error' in response: | 4069 | if isinstance(response, dict) and 'error' in response: |
3947 | error_msg = response['error'] | 4070 | error_msg = response['error'] |
3948 | elif isinstance(response, str): | 4071 | elif isinstance(response, str): |
@@ -4348,6 +4471,14 @@ class Mastodon: | |||
4348 | base_url = base_url.rstrip("/") | 4471 | base_url = base_url.rstrip("/") |
4349 | return base_url | 4472 | return base_url |
4350 | 4473 | ||
4474 | @staticmethod | ||
4475 | def __deprotocolize(base_url): | ||
4476 | """Internal helper to strip http and https from a URL""" | ||
4477 | if base_url.startswith("http://"): | ||
4478 | base_url = base_url[7:] | ||
4479 | elif base_url.startswith("https://") or base_url.startswith("onion://"): | ||
4480 | base_url = base_url[8:] | ||
4481 | return base_url | ||
4351 | 4482 | ||
4352 | ## | 4483 | ## |
4353 | # Exceptions | 4484 | # Exceptions |