aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mastodon')
-rw-r--r--mastodon/Mastodon.py469
-rw-r--r--mastodon/streaming.py117
2 files changed, 350 insertions, 236 deletions
diff --git a/mastodon/Mastodon.py b/mastodon/Mastodon.py
index 8dcdf1b..a2986cb 100644
--- a/mastodon/Mastodon.py
+++ b/mastodon/Mastodon.py
@@ -229,30 +229,25 @@ class Mastodon:
229 __DICT_VERSION_HASHTAG = "2.3.4" 229 __DICT_VERSION_HASHTAG = "2.3.4"
230 __DICT_VERSION_EMOJI = "3.0.0" 230 __DICT_VERSION_EMOJI = "3.0.0"
231 __DICT_VERSION_RELATIONSHIP = "3.3.0" 231 __DICT_VERSION_RELATIONSHIP = "3.3.0"
232 __DICT_VERSION_NOTIFICATION = bigger_version(bigger_version( 232 __DICT_VERSION_NOTIFICATION = bigger_version(bigger_version("1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS)
233 "1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS)
234 __DICT_VERSION_CONTEXT = bigger_version("1.0.0", __DICT_VERSION_STATUS) 233 __DICT_VERSION_CONTEXT = bigger_version("1.0.0", __DICT_VERSION_STATUS)
235 __DICT_VERSION_LIST = "2.1.0" 234 __DICT_VERSION_LIST = "2.1.0"
236 __DICT_VERSION_CARD = "3.2.0" 235 __DICT_VERSION_CARD = "3.2.0"
237 __DICT_VERSION_SEARCHRESULT = bigger_version(bigger_version(bigger_version( 236 __DICT_VERSION_SEARCHRESULT = bigger_version(bigger_version(bigger_version("1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS), __DICT_VERSION_HASHTAG)
238 "1.0.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS), __DICT_VERSION_HASHTAG)
239 __DICT_VERSION_ACTIVITY = "2.1.2" 237 __DICT_VERSION_ACTIVITY = "2.1.2"
240 __DICT_VERSION_REPORT = "2.9.1" 238 __DICT_VERSION_REPORT = "2.9.1"
241 __DICT_VERSION_PUSH = "2.4.0" 239 __DICT_VERSION_PUSH = "2.4.0"
242 __DICT_VERSION_PUSH_NOTIF = "2.4.0" 240 __DICT_VERSION_PUSH_NOTIF = "2.4.0"
243 __DICT_VERSION_FILTER = "2.4.3" 241 __DICT_VERSION_FILTER = "2.4.3"
244 __DICT_VERSION_CONVERSATION = bigger_version(bigger_version( 242 __DICT_VERSION_CONVERSATION = bigger_version(bigger_version("2.6.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS)
245 "2.6.0", __DICT_VERSION_ACCOUNT), __DICT_VERSION_STATUS) 243 __DICT_VERSION_SCHEDULED_STATUS = bigger_version("2.7.0", __DICT_VERSION_STATUS)
246 __DICT_VERSION_SCHEDULED_STATUS = bigger_version(
247 "2.7.0", __DICT_VERSION_STATUS)
248 __DICT_VERSION_PREFERENCES = "2.8.0" 244 __DICT_VERSION_PREFERENCES = "2.8.0"
249 __DICT_VERSION_ADMIN_ACCOUNT = bigger_version( 245 __DICT_VERSION_ADMIN_ACCOUNT = bigger_version("2.9.1", __DICT_VERSION_ACCOUNT)
250 "2.9.1", __DICT_VERSION_ACCOUNT)
251 __DICT_VERSION_FEATURED_TAG = "3.0.0" 246 __DICT_VERSION_FEATURED_TAG = "3.0.0"
252 __DICT_VERSION_MARKER = "3.0.0" 247 __DICT_VERSION_MARKER = "3.0.0"
253 __DICT_VERSION_REACTION = "3.1.0" 248 __DICT_VERSION_REACTION = "3.1.0"
254 __DICT_VERSION_ANNOUNCEMENT = bigger_version( 249 __DICT_VERSION_ANNOUNCEMENT = bigger_version("3.1.0", __DICT_VERSION_REACTION)
255 "3.1.0", __DICT_VERSION_REACTION) 250 __DICT_VERSION_STATUS_EDIT = "3.5.0"
256 251
257 ### 252 ###
258 # Registering apps 253 # Registering apps
@@ -378,7 +373,7 @@ class Mastodon:
378 If no other `User-Agent` is specified, "mastodonpy" will be used. 373 If no other `User-Agent` is specified, "mastodonpy" will be used.
379 """ 374 """
380 self.api_base_url = None 375 self.api_base_url = None
381 if not api_base_url is None: 376 if api_base_url is not None:
382 self.api_base_url = Mastodon.__protocolize(api_base_url) 377 self.api_base_url = Mastodon.__protocolize(api_base_url)
383 378
384 self.client_id = client_id 379 self.client_id = client_id
@@ -419,7 +414,7 @@ class Mastodon:
419 self.client_secret = secret_file.readline().rstrip() 414 self.client_secret = secret_file.readline().rstrip()
420 415
421 try_base_url = secret_file.readline().rstrip() 416 try_base_url = secret_file.readline().rstrip()
422 if (not try_base_url is None) and len(try_base_url) != 0: 417 if try_base_url is not None and len(try_base_url) != 0:
423 try_base_url = Mastodon.__protocolize(try_base_url) 418 try_base_url = Mastodon.__protocolize(try_base_url)
424 if not (self.api_base_url is None or try_base_url == self.api_base_url): 419 if not (self.api_base_url is None or try_base_url == self.api_base_url):
425 raise MastodonIllegalArgumentError( 420 raise MastodonIllegalArgumentError(
@@ -440,7 +435,7 @@ class Mastodon:
440 self.access_token = token_file.readline().rstrip() 435 self.access_token = token_file.readline().rstrip()
441 436
442 try_base_url = token_file.readline().rstrip() 437 try_base_url = token_file.readline().rstrip()
443 if (not try_base_url is None) and len(try_base_url) != 0: 438 if try_base_url is not None and len(try_base_url) != 0:
444 try_base_url = Mastodon.__protocolize(try_base_url) 439 try_base_url = Mastodon.__protocolize(try_base_url)
445 if not (self.api_base_url is None or try_base_url == self.api_base_url): 440 if not (self.api_base_url is None or try_base_url == self.api_base_url):
446 raise MastodonIllegalArgumentError( 441 raise MastodonIllegalArgumentError(
@@ -457,7 +452,7 @@ class Mastodon:
457 self.version_check_worked = None 452 self.version_check_worked = None
458 453
459 # Versioning 454 # Versioning
460 if mastodon_version == None and self.version_check_mode != 'none': 455 if mastodon_version is None and self.version_check_mode != 'none':
461 self.retrieve_mastodon_version() 456 self.retrieve_mastodon_version()
462 elif self.version_check_mode != 'none': 457 elif self.version_check_mode != 'none':
463 try: 458 try:
@@ -632,7 +627,7 @@ class Mastodon:
632 self.__logged_in_id = None 627 self.__logged_in_id = None
633 628
634 # Retry version check if needed (might be required in limited federation mode) 629 # Retry version check if needed (might be required in limited federation mode)
635 if self.version_check_worked == False: 630 if not self.version_check_worked:
636 self.retrieve_mastodon_version() 631 self.retrieve_mastodon_version()
637 632
638 return response['access_token'] 633 return response['access_token']
@@ -698,7 +693,7 @@ class Mastodon:
698 params['client_id'] = self.client_id 693 params['client_id'] = self.client_id
699 params['client_secret'] = self.client_secret 694 params['client_secret'] = self.client_secret
700 695
701 if agreement == False: 696 if not agreement:
702 del params['agreement'] 697 del params['agreement']
703 698
704 # Step 1: Get a user-free token via oauth 699 # Step 1: Get a user-free token via oauth
@@ -865,24 +860,24 @@ class Mastodon:
865 860
866 Returns a list of `toot dicts`_. 861 Returns a list of `toot dicts`_.
867 """ 862 """
868 if max_id != None: 863 if max_id is not None:
869 max_id = self.__unpack_id(max_id, dateconv=True) 864 max_id = self.__unpack_id(max_id, dateconv=True)
870 865
871 if min_id != None: 866 if min_id is not None:
872 min_id = self.__unpack_id(min_id, dateconv=True) 867 min_id = self.__unpack_id(min_id, dateconv=True)
873 868
874 if since_id != None: 869 if since_id is not None:
875 since_id = self.__unpack_id(since_id, dateconv=True) 870 since_id = self.__unpack_id(since_id, dateconv=True)
876 871
877 params_initial = locals() 872 params_initial = locals()
878 873
879 if local == False: 874 if not local:
880 del params_initial['local'] 875 del params_initial['local']
881 876
882 if remote == False: 877 if not remote:
883 del params_initial['remote'] 878 del params_initial['remote']
884 879
885 if only_media == False: 880 if not only_media:
886 del params_initial['only_media'] 881 del params_initial['only_media']
887 882
888 if timeline == "local": 883 if timeline == "local":
@@ -950,13 +945,13 @@ class Mastodon:
950 945
951 Returns a list of `conversation dicts`_. 946 Returns a list of `conversation dicts`_.
952 """ 947 """
953 if max_id != None: 948 if max_id is not None:
954 max_id = self.__unpack_id(max_id, dateconv=True) 949 max_id = self.__unpack_id(max_id, dateconv=True)
955 950
956 if min_id != None: 951 if min_id is not None:
957 min_id = self.__unpack_id(min_id, dateconv=True) 952 min_id = self.__unpack_id(min_id, dateconv=True)
958 953
959 if since_id != None: 954 if since_id is not None:
960 since_id = self.__unpack_id(since_id, dateconv=True) 955 since_id = self.__unpack_id(since_id, dateconv=True)
961 956
962 params = self.__generate_params(locals()) 957 params = self.__generate_params(locals())
@@ -1093,8 +1088,8 @@ class Mastodon:
1093 1088
1094 Returns a list of `notification dicts`_. 1089 Returns a list of `notification dicts`_.
1095 """ 1090 """
1096 if not mentions_only is None: 1091 if mentions_only is not None:
1097 if not exclude_types is None: 1092 if exclude_types is not None:
1098 if mentions_only: 1093 if mentions_only:
1099 exclude_types = ["follow", "favourite", 1094 exclude_types = ["follow", "favourite",
1100 "reblog", "poll", "follow_request"] 1095 "reblog", "poll", "follow_request"]
@@ -1103,16 +1098,16 @@ class Mastodon:
1103 'Cannot specify exclude_types when mentions_only is present') 1098 'Cannot specify exclude_types when mentions_only is present')
1104 del mentions_only 1099 del mentions_only
1105 1100
1106 if max_id != None: 1101 if max_id is not None:
1107 max_id = self.__unpack_id(max_id, dateconv=True) 1102 max_id = self.__unpack_id(max_id, dateconv=True)
1108 1103
1109 if min_id != None: 1104 if min_id is not None:
1110 min_id = self.__unpack_id(min_id, dateconv=True) 1105 min_id = self.__unpack_id(min_id, dateconv=True)
1111 1106
1112 if since_id != None: 1107 if since_id is not None:
1113 since_id = self.__unpack_id(since_id, dateconv=True) 1108 since_id = self.__unpack_id(since_id, dateconv=True)
1114 1109
1115 if account_id != None: 1110 if account_id is not None:
1116 account_id = self.__unpack_id(account_id) 1111 account_id = self.__unpack_id(account_id)
1117 1112
1118 if id is None: 1113 if id is None:
@@ -1178,23 +1173,23 @@ class Mastodon:
1178 Returns a list of `toot dicts`_. 1173 Returns a list of `toot dicts`_.
1179 """ 1174 """
1180 id = self.__unpack_id(id) 1175 id = self.__unpack_id(id)
1181 if max_id != None: 1176 if max_id is not None:
1182 max_id = self.__unpack_id(max_id, dateconv=True) 1177 max_id = self.__unpack_id(max_id, dateconv=True)
1183 1178
1184 if min_id != None: 1179 if min_id is not None:
1185 min_id = self.__unpack_id(min_id, dateconv=True) 1180 min_id = self.__unpack_id(min_id, dateconv=True)
1186 1181
1187 if since_id != None: 1182 if since_id is not None:
1188 since_id = self.__unpack_id(since_id, dateconv=True) 1183 since_id = self.__unpack_id(since_id, dateconv=True)
1189 1184
1190 params = self.__generate_params(locals(), ['id']) 1185 params = self.__generate_params(locals(), ['id'])
1191 if pinned == False: 1186 if not pinned:
1192 del params["pinned"] 1187 del params["pinned"]
1193 if only_media == False: 1188 if not only_media:
1194 del params["only_media"] 1189 del params["only_media"]
1195 if exclude_replies == False: 1190 if not exclude_replies:
1196 del params["exclude_replies"] 1191 del params["exclude_replies"]
1197 if exclude_reblogs == False: 1192 if not exclude_reblogs:
1198 del params["exclude_reblogs"] 1193 del params["exclude_reblogs"]
1199 1194
1200 url = '/api/v1/accounts/{0}/statuses'.format(str(id)) 1195 url = '/api/v1/accounts/{0}/statuses'.format(str(id))
@@ -1208,13 +1203,13 @@ class Mastodon:
1208 Returns a list of `user dicts`_. 1203 Returns a list of `user dicts`_.
1209 """ 1204 """
1210 id = self.__unpack_id(id) 1205 id = self.__unpack_id(id)
1211 if max_id != None: 1206 if max_id is not None:
1212 max_id = self.__unpack_id(max_id, dateconv=True) 1207 max_id = self.__unpack_id(max_id, dateconv=True)
1213 1208
1214 if min_id != None: 1209 if min_id is not None:
1215 min_id = self.__unpack_id(min_id, dateconv=True) 1210 min_id = self.__unpack_id(min_id, dateconv=True)
1216 1211
1217 if since_id != None: 1212 if since_id is not None:
1218 since_id = self.__unpack_id(since_id, dateconv=True) 1213 since_id = self.__unpack_id(since_id, dateconv=True)
1219 1214
1220 params = self.__generate_params(locals(), ['id']) 1215 params = self.__generate_params(locals(), ['id'])
@@ -1229,13 +1224,13 @@ class Mastodon:
1229 Returns a list of `user dicts`_. 1224 Returns a list of `user dicts`_.
1230 """ 1225 """
1231 id = self.__unpack_id(id) 1226 id = self.__unpack_id(id)
1232 if max_id != None: 1227 if max_id is not None:
1233 max_id = self.__unpack_id(max_id, dateconv=True) 1228 max_id = self.__unpack_id(max_id, dateconv=True)
1234 1229
1235 if min_id != None: 1230 if min_id is not None:
1236 min_id = self.__unpack_id(min_id, dateconv=True) 1231 min_id = self.__unpack_id(min_id, dateconv=True)
1237 1232
1238 if since_id != None: 1233 if since_id is not None:
1239 since_id = self.__unpack_id(since_id, dateconv=True) 1234 since_id = self.__unpack_id(since_id, dateconv=True)
1240 1235
1241 params = self.__generate_params(locals(), ['id']) 1236 params = self.__generate_params(locals(), ['id'])
@@ -1359,7 +1354,7 @@ class Mastodon:
1359 continue 1354 continue
1360 1355
1361 filter_string = re.escape(keyword_filter["phrase"]) 1356 filter_string = re.escape(keyword_filter["phrase"])
1362 if keyword_filter["whole_word"] == True: 1357 if keyword_filter["whole_word"]:
1363 filter_string = "\\b" + filter_string + "\\b" 1358 filter_string = "\\b" + filter_string + "\\b"
1364 filter_strings.append(filter_string) 1359 filter_strings.append(filter_string)
1365 filter_re = re.compile("|".join(filter_strings), flags=re.IGNORECASE) 1360 filter_re = re.compile("|".join(filter_strings), flags=re.IGNORECASE)
@@ -1435,8 +1430,8 @@ class Mastodon:
1435 Internal Helper: Throw a MastodonVersionError if version is < 2.8.0 but parameters 1430 Internal Helper: Throw a MastodonVersionError if version is < 2.8.0 but parameters
1436 for search that are available only starting with 2.8.0 are specified. 1431 for search that are available only starting with 2.8.0 are specified.
1437 """ 1432 """
1438 if not account_id is None or not offset is None or not min_id is None or not max_id is None: 1433 if any(item is not None for item in (account_id, offset, min_id, max_id)):
1439 if self.verify_minimum_version("2.8.0", cached=True) == False: 1434 if not self.verify_minimum_version("2.8.0", cached=True):
1440 raise MastodonVersionError("Advanced search parameters require Mastodon 2.8.0+") 1435 raise MastodonVersionError("Advanced search parameters require Mastodon 2.8.0+")
1441 1436
1442 @api_version("1.1.0", "2.8.0", __DICT_VERSION_SEARCHRESULT) 1437 @api_version("1.1.0", "2.8.0", __DICT_VERSION_SEARCHRESULT)
@@ -1465,7 +1460,7 @@ class Mastodon:
1465 1460
1466 Returns a `search result dict`_, with tags as `hashtag dicts`_. 1461 Returns a `search result dict`_, with tags as `hashtag dicts`_.
1467 """ 1462 """
1468 if self.verify_minimum_version("2.4.1", cached=True) == True: 1463 if self.verify_minimum_version("2.4.1", cached=True):
1469 return self.search_v2(q, resolve=resolve, result_type=result_type, account_id=account_id, offset=offset, min_id=min_id, max_id=max_id) 1464 return self.search_v2(q, resolve=resolve, result_type=result_type, account_id=account_id, offset=offset, min_id=min_id, max_id=max_id)
1470 else: 1465 else:
1471 self.__ensure_search_params_acceptable( 1466 self.__ensure_search_params_acceptable(
@@ -1481,7 +1476,7 @@ class Mastodon:
1481 Returns a `search result dict`_. 1476 Returns a `search result dict`_.
1482 """ 1477 """
1483 params = self.__generate_params(locals()) 1478 params = self.__generate_params(locals())
1484 if resolve == False: 1479 if not resolve:
1485 del params['resolve'] 1480 del params['resolve']
1486 return self.__api_request('GET', '/api/v1/search', params) 1481 return self.__api_request('GET', '/api/v1/search', params)
1487 1482
@@ -1499,10 +1494,10 @@ class Mastodon:
1499 account_id, offset, min_id, max_id) 1494 account_id, offset, min_id, max_id)
1500 params = self.__generate_params(locals()) 1495 params = self.__generate_params(locals())
1501 1496
1502 if resolve == False: 1497 if not resolve:
1503 del params["resolve"] 1498 del params["resolve"]
1504 1499
1505 if exclude_unreviewed == False or not self.verify_minimum_version("3.0.0", cached=True): 1500 if not exclude_unreviewed or not self.verify_minimum_version("3.0.0", cached=True):
1506 del params["exclude_unreviewed"] 1501 del params["exclude_unreviewed"]
1507 1502
1508 if "result_type" in params: 1503 if "result_type" in params:
@@ -1564,13 +1559,13 @@ class Mastodon:
1564 """ 1559 """
1565 id = self.__unpack_id(id) 1560 id = self.__unpack_id(id)
1566 1561
1567 if max_id != None: 1562 if max_id is not None:
1568 max_id = self.__unpack_id(max_id, dateconv=True) 1563 max_id = self.__unpack_id(max_id, dateconv=True)
1569 1564
1570 if min_id != None: 1565 if min_id is not None:
1571 min_id = self.__unpack_id(min_id, dateconv=True) 1566 min_id = self.__unpack_id(min_id, dateconv=True)
1572 1567
1573 if since_id != None: 1568 if since_id is not None:
1574 since_id = self.__unpack_id(since_id, dateconv=True) 1569 since_id = self.__unpack_id(since_id, dateconv=True)
1575 1570
1576 params = self.__generate_params(locals(), ['id']) 1571 params = self.__generate_params(locals(), ['id'])
@@ -1586,13 +1581,13 @@ class Mastodon:
1586 1581
1587 Returns a list of `user dicts`_. 1582 Returns a list of `user dicts`_.
1588 """ 1583 """
1589 if max_id != None: 1584 if max_id is not None:
1590 max_id = self.__unpack_id(max_id, dateconv=True) 1585 max_id = self.__unpack_id(max_id, dateconv=True)
1591 1586
1592 if min_id != None: 1587 if min_id is not None:
1593 min_id = self.__unpack_id(min_id, dateconv=True) 1588 min_id = self.__unpack_id(min_id, dateconv=True)
1594 1589
1595 if since_id != None: 1590 if since_id is not None:
1596 since_id = self.__unpack_id(since_id, dateconv=True) 1591 since_id = self.__unpack_id(since_id, dateconv=True)
1597 1592
1598 params = self.__generate_params(locals()) 1593 params = self.__generate_params(locals())
@@ -1605,13 +1600,13 @@ class Mastodon:
1605 1600
1606 Returns a list of `user dicts`_. 1601 Returns a list of `user dicts`_.
1607 """ 1602 """
1608 if max_id != None: 1603 if max_id is not None:
1609 max_id = self.__unpack_id(max_id, dateconv=True) 1604 max_id = self.__unpack_id(max_id, dateconv=True)
1610 1605
1611 if min_id != None: 1606 if min_id is not None:
1612 min_id = self.__unpack_id(min_id, dateconv=True) 1607 min_id = self.__unpack_id(min_id, dateconv=True)
1613 1608
1614 if since_id != None: 1609 if since_id is not None:
1615 since_id = self.__unpack_id(since_id, dateconv=True) 1610 since_id = self.__unpack_id(since_id, dateconv=True)
1616 1611
1617 params = self.__generate_params(locals()) 1612 params = self.__generate_params(locals())
@@ -1642,13 +1637,13 @@ class Mastodon:
1642 1637
1643 Returns a list of `toot dicts`_. 1638 Returns a list of `toot dicts`_.
1644 """ 1639 """
1645 if max_id != None: 1640 if max_id is not None:
1646 max_id = self.__unpack_id(max_id, dateconv=True) 1641 max_id = self.__unpack_id(max_id, dateconv=True)
1647 1642
1648 if min_id != None: 1643 if min_id is not None:
1649 min_id = self.__unpack_id(min_id, dateconv=True) 1644 min_id = self.__unpack_id(min_id, dateconv=True)
1650 1645
1651 if since_id != None: 1646 if since_id is not None:
1652 since_id = self.__unpack_id(since_id, dateconv=True) 1647 since_id = self.__unpack_id(since_id, dateconv=True)
1653 1648
1654 params = self.__generate_params(locals()) 1649 params = self.__generate_params(locals())
@@ -1664,13 +1659,13 @@ class Mastodon:
1664 1659
1665 Returns a list of `user dicts`_. 1660 Returns a list of `user dicts`_.
1666 """ 1661 """
1667 if max_id != None: 1662 if max_id is not None:
1668 max_id = self.__unpack_id(max_id, dateconv=True) 1663 max_id = self.__unpack_id(max_id, dateconv=True)
1669 1664
1670 if min_id != None: 1665 if min_id is not None:
1671 min_id = self.__unpack_id(min_id, dateconv=True) 1666 min_id = self.__unpack_id(min_id, dateconv=True)
1672 1667
1673 if since_id != None: 1668 if since_id is not None:
1674 since_id = self.__unpack_id(since_id, dateconv=True) 1669 since_id = self.__unpack_id(since_id, dateconv=True)
1675 1670
1676 params = self.__generate_params(locals()) 1671 params = self.__generate_params(locals())
@@ -1686,13 +1681,13 @@ class Mastodon:
1686 1681
1687 Returns a list of blocked domain URLs (as strings, without protocol specifier). 1682 Returns a list of blocked domain URLs (as strings, without protocol specifier).
1688 """ 1683 """
1689 if max_id != None: 1684 if max_id is not None:
1690 max_id = self.__unpack_id(max_id, dateconv=True) 1685 max_id = self.__unpack_id(max_id, dateconv=True)
1691 1686
1692 if min_id != None: 1687 if min_id is not None:
1693 min_id = self.__unpack_id(min_id, dateconv=True) 1688 min_id = self.__unpack_id(min_id, dateconv=True)
1694 1689
1695 if since_id != None: 1690 if since_id is not None:
1696 since_id = self.__unpack_id(since_id, dateconv=True) 1691 since_id = self.__unpack_id(since_id, dateconv=True)
1697 1692
1698 params = self.__generate_params(locals()) 1693 params = self.__generate_params(locals())
@@ -1792,13 +1787,13 @@ class Mastodon:
1792 1787
1793 Returns a list of `toot dicts`_. 1788 Returns a list of `toot dicts`_.
1794 """ 1789 """
1795 if max_id != None: 1790 if max_id is not None:
1796 max_id = self.__unpack_id(max_id, dateconv=True) 1791 max_id = self.__unpack_id(max_id, dateconv=True)
1797 1792
1798 if min_id != None: 1793 if min_id is not None:
1799 min_id = self.__unpack_id(min_id, dateconv=True) 1794 min_id = self.__unpack_id(min_id, dateconv=True)
1800 1795
1801 if since_id != None: 1796 if since_id is not None:
1802 since_id = self.__unpack_id(since_id, dateconv=True) 1797 since_id = self.__unpack_id(since_id, dateconv=True)
1803 1798
1804 params = self.__generate_params(locals()) 1799 params = self.__generate_params(locals())
@@ -1807,6 +1802,82 @@ class Mastodon:
1807 ### 1802 ###
1808 # Writing data: Statuses 1803 # Writing data: Statuses
1809 ### 1804 ###
1805 def __status_internal(self, status, in_reply_to_id=None, media_ids=None,
1806 sensitive=False, visibility=None, spoiler_text=None,
1807 language=None, idempotency_key=None, content_type=None,
1808 scheduled_at=None, poll=None, quote_id=None, edit=False):
1809 if quote_id is not None:
1810 if self.feature_set != "fedibird":
1811 raise MastodonIllegalArgumentError('quote_id is only available with feature set fedibird')
1812 quote_id = self.__unpack_id(quote_id)
1813
1814 if content_type is not None:
1815 if self.feature_set != "pleroma":
1816 raise MastodonIllegalArgumentError('content_type is only available with feature set pleroma')
1817 # It would be better to read this from nodeinfo and cache, but this is easier
1818 if not content_type in ["text/plain", "text/html", "text/markdown", "text/bbcode"]:
1819 raise MastodonIllegalArgumentError('Invalid content type specified')
1820
1821 if in_reply_to_id is not None:
1822 in_reply_to_id = self.__unpack_id(in_reply_to_id)
1823
1824 if scheduled_at is not None:
1825 scheduled_at = self.__consistent_isoformat_utc(scheduled_at)
1826
1827 params_initial = locals()
1828
1829 # Validate poll/media exclusivity
1830 if poll is not None:
1831 if media_ids is not None and len(media_ids) != 0:
1832 raise ValueError(
1833 'Status can have media or poll attached - not both.')
1834
1835 # Validate visibility parameter
1836 valid_visibilities = ['private', 'public', 'unlisted', 'direct']
1837 if params_initial['visibility'] is None:
1838 del params_initial['visibility']
1839 else:
1840 params_initial['visibility'] = params_initial['visibility'].lower()
1841 if params_initial['visibility'] not in valid_visibilities:
1842 raise ValueError('Invalid visibility value! Acceptable values are %s' % valid_visibilities)
1843
1844 if params_initial['language'] is None:
1845 del params_initial['language']
1846
1847 if params_initial['sensitive'] is False:
1848 del [params_initial['sensitive']]
1849
1850 headers = {}
1851 if idempotency_key is not None:
1852 headers['Idempotency-Key'] = idempotency_key
1853
1854 if media_ids is not None:
1855 try:
1856 media_ids_proper = []
1857 if not isinstance(media_ids, (list, tuple)):
1858 media_ids = [media_ids]
1859 for media_id in media_ids:
1860 media_ids_proper.append(self.__unpack_id(media_id))
1861 except Exception as e:
1862 raise MastodonIllegalArgumentError("Invalid media dict: %s" % e)
1863
1864 params_initial["media_ids"] = media_ids_proper
1865
1866 if params_initial['content_type'] is None:
1867 del params_initial['content_type']
1868
1869 use_json = False
1870 if poll is not None:
1871 use_json = True
1872
1873 params = self.__generate_params(params_initial, ['idempotency_key', 'edit'])
1874 if edit is None:
1875 # Post
1876 return self.__api_request('POST', '/api/v1/statuses', params, headers=headers, use_json=use_json)
1877 else:
1878 # Edit
1879 return self.__api_request('PUT', '/api/v1/statuses/{0}'.format(str(self.__unpack_id(edit))), params, headers=headers, use_json=use_json)
1880
1810 @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) 1881 @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS)
1811 def status_post(self, status, in_reply_to_id=None, media_ids=None, 1882 def status_post(self, status, in_reply_to_id=None, media_ids=None,
1812 sensitive=False, visibility=None, spoiler_text=None, 1883 sensitive=False, visibility=None, spoiler_text=None,
@@ -1867,77 +1938,21 @@ class Mastodon:
1867 1938
1868 Returns a `toot dict`_ with the new status. 1939 Returns a `toot dict`_ with the new status.
1869 """ 1940 """
1870 if quote_id != None: 1941 return self.__status_internal(
1871 if self.feature_set != "fedibird": 1942 status,
1872 raise MastodonIllegalArgumentError( 1943 in_reply_to_id,
1873 'quote_id is only available with feature set fedibird') 1944 media_ids,
1874 quote_id = self.__unpack_id(quote_id) 1945 sensitive,
1875 1946 visibility,
1876 if content_type != None: 1947 spoiler_text,
1877 if self.feature_set != "pleroma": 1948 language,
1878 raise MastodonIllegalArgumentError( 1949 idempotency_key,
1879 'content_type is only available with feature set pleroma') 1950 content_type,
1880 # It would be better to read this from nodeinfo and cache, but this is easier 1951 scheduled_at,
1881 if not content_type in ["text/plain", "text/html", "text/markdown", "text/bbcode"]: 1952 poll,
1882 raise MastodonIllegalArgumentError( 1953 quote_id,
1883 'Invalid content type specified') 1954 edit=None
1884 1955 )
1885 if in_reply_to_id != None:
1886 in_reply_to_id = self.__unpack_id(in_reply_to_id)
1887
1888 if scheduled_at != None:
1889 scheduled_at = self.__consistent_isoformat_utc(scheduled_at)
1890
1891 params_initial = locals()
1892
1893 # Validate poll/media exclusivity
1894 if not poll is None:
1895 if (not media_ids is None) and len(media_ids) != 0:
1896 raise ValueError(
1897 'Status can have media or poll attached - not both.')
1898
1899 # Validate visibility parameter
1900 valid_visibilities = ['private', 'public', 'unlisted', 'direct']
1901 if params_initial['visibility'] == None:
1902 del params_initial['visibility']
1903 else:
1904 params_initial['visibility'] = params_initial['visibility'].lower()
1905 if params_initial['visibility'] not in valid_visibilities:
1906 raise ValueError('Invalid visibility value! Acceptable '
1907 'values are %s' % valid_visibilities)
1908
1909 if params_initial['language'] == None:
1910 del params_initial['language']
1911
1912 if params_initial['sensitive'] is False:
1913 del [params_initial['sensitive']]
1914
1915 headers = {}
1916 if idempotency_key != None:
1917 headers['Idempotency-Key'] = idempotency_key
1918
1919 if media_ids is not None:
1920 try:
1921 media_ids_proper = []
1922 if not isinstance(media_ids, (list, tuple)):
1923 media_ids = [media_ids]
1924 for media_id in media_ids:
1925 media_ids_proper.append(self.__unpack_id(media_id))
1926 except Exception as e:
1927 raise MastodonIllegalArgumentError("Invalid media "
1928 "dict: %s" % e)
1929
1930 params_initial["media_ids"] = media_ids_proper
1931
1932 if params_initial['content_type'] == None:
1933 del params_initial['content_type']
1934
1935 use_json = False
1936 if not poll is None:
1937 use_json = True
1938
1939 params = self.__generate_params(params_initial, ['idempotency_key'])
1940 return self.__api_request('POST', '/api/v1/statuses', params, headers=headers, use_json=use_json)
1941 1956
1942 @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) 1957 @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS)
1943 def toot(self, status): 1958 def toot(self, status):
@@ -1950,6 +1965,45 @@ class Mastodon:
1950 """ 1965 """
1951 return self.status_post(status) 1966 return self.status_post(status)
1952 1967
1968 @api_version("3.5.0", "3.5.0", __DICT_VERSION_STATUS)
1969 def status_update(self, id, status = None, spoiler_text = None, sensitive = None, media_ids = None, poll = None):
1970 """
1971 Edit a status. The meanings of the fields are largely the same as in `status_post()`_,
1972 though not every field can be edited.
1973
1974 Note that editing a poll will reset the votes.
1975 """
1976 return self.__status_internal(
1977 status = status,
1978 media_ids = media_ids,
1979 sensitive = sensitive,
1980 spoiler_text = spoiler_text,
1981 poll = poll,
1982 edit = id
1983 )
1984
1985 @api_version("3.5.0", "3.5.0", __DICT_VERSION_STATUS_EDIT)
1986 def status_history(self, id):
1987 """
1988 Returns the edit history of a status as a list of `status edit dicts`_, starting
1989 from the original form. Note that this means that a status that has been edited
1990 once will have *two* entries in this list, a status that has been edited twice
1991 will have three, and so on.
1992 """
1993 id = self.__unpack_id(id)
1994 return self.__api_request('GET', "/api/v1/statuses/{0}/history".format(str(id)))
1995
1996 def status_source(self, id):
1997 """
1998 Returns the source of a status for editing.
1999
2000 Return value is a dictionary containing exactly the parameters you could pass to
2001 `status_update()`_ to change nothing about the status, except `status` is `text`
2002 instead.
2003 """
2004 id = self.__unpack_id(id)
2005 return self.__api_request('GET', "/api/v1/statuses/{0}/source".format(str(id)))
2006
1953 @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS) 2007 @api_version("1.0.0", "2.8.0", __DICT_VERSION_STATUS)
1954 def status_reply(self, to_status, status, in_reply_to_id=None, media_ids=None, 2008 def status_reply(self, to_status, status, in_reply_to_id=None, media_ids=None,
1955 sensitive=False, visibility=None, spoiler_text=None, 2009 sensitive=False, visibility=None, spoiler_text=None,
@@ -1985,9 +2039,9 @@ class Mastodon:
1985 mentioned_accounts.values())) + status 2039 mentioned_accounts.values())) + status
1986 2040
1987 # Retain visibility / cw 2041 # Retain visibility / cw
1988 if visibility == None and 'visibility' in to_status: 2042 if visibility is None and 'visibility' in to_status:
1989 visibility = to_status.visibility 2043 visibility = to_status.visibility
1990 if spoiler_text == None and 'spoiler_text' in to_status: 2044 if spoiler_text is None and 'spoiler_text' in to_status:
1991 spoiler_text = to_status.spoiler_text 2045 spoiler_text = to_status.spoiler_text
1992 2046
1993 keyword_args["status"] = status 2047 keyword_args["status"] = status
@@ -2251,9 +2305,9 @@ class Mastodon:
2251 Returns a `relationship dict`_ containing the updated relationship to the user. 2305 Returns a `relationship dict`_ containing the updated relationship to the user.
2252 """ 2306 """
2253 id = self.__unpack_id(id) 2307 id = self.__unpack_id(id)
2254 params = self.__generate_params(locals()) 2308 params = self.__generate_params(locals(), ["id"])
2255 2309
2256 if params["reblogs"] == None: 2310 if params["reblogs"] is None:
2257 del params["reblogs"] 2311 del params["reblogs"]
2258 2312
2259 url = '/api/v1/accounts/{0}/follow'.format(str(id)) 2313 url = '/api/v1/accounts/{0}/follow'.format(str(id))
@@ -2357,7 +2411,7 @@ class Mastodon:
2357 params_initial = collections.OrderedDict(locals()) 2411 params_initial = collections.OrderedDict(locals())
2358 2412
2359 # Convert fields 2413 # Convert fields
2360 if fields != None: 2414 if fields is not None:
2361 if len(fields) > 4: 2415 if len(fields) > 4:
2362 raise MastodonIllegalArgumentError( 2416 raise MastodonIllegalArgumentError(
2363 'A maximum of four fields are allowed.') 2417 'A maximum of four fields are allowed.')
@@ -2376,9 +2430,9 @@ class Mastodon:
2376 2430
2377 # Create file info 2431 # Create file info
2378 files = {} 2432 files = {}
2379 if not avatar is None: 2433 if avatar is not None:
2380 files["avatar"] = self.__load_media_file(avatar, avatar_mime_type) 2434 files["avatar"] = self.__load_media_file(avatar, avatar_mime_type)
2381 if not header is None: 2435 if header is not None:
2382 files["header"] = self.__load_media_file(header, header_mime_type) 2436 files["header"] = self.__load_media_file(header, header_mime_type)
2383 2437
2384 params = self.__generate_params(params_initial) 2438 params = self.__generate_params(params_initial)
@@ -2591,13 +2645,13 @@ class Mastodon:
2591 """ 2645 """
2592 account_id = self.__unpack_id(account_id) 2646 account_id = self.__unpack_id(account_id)
2593 2647
2594 if not status_ids is None: 2648 if status_ids is not None:
2595 if not isinstance(status_ids, list): 2649 if not isinstance(status_ids, list):
2596 status_ids = [status_ids] 2650 status_ids = [status_ids]
2597 status_ids = list(map(lambda x: self.__unpack_id(x), status_ids)) 2651 status_ids = list(map(lambda x: self.__unpack_id(x), status_ids))
2598 2652
2599 params_initial = locals() 2653 params_initial = locals()
2600 if forward == False: 2654 if not forward:
2601 del params_initial['forward'] 2655 del params_initial['forward']
2602 2656
2603 params = self.__generate_params(params_initial) 2657 params = self.__generate_params(params_initial)
@@ -2663,10 +2717,10 @@ class Mastodon:
2663 files = {'file': self.__load_media_file( 2717 files = {'file': self.__load_media_file(
2664 media_file, mime_type, file_name)} 2718 media_file, mime_type, file_name)}
2665 2719
2666 if focus != None: 2720 if focus is not None:
2667 focus = str(focus[0]) + "," + str(focus[1]) 2721 focus = str(focus[0]) + "," + str(focus[1])
2668 2722
2669 if not thumbnail is None: 2723 if thumbnail is not None:
2670 if not self.verify_minimum_version("3.2.0", cached=True): 2724 if not self.verify_minimum_version("3.2.0", cached=True):
2671 raise MastodonVersionError( 2725 raise MastodonVersionError(
2672 'Thumbnail requires version > 3.2.0') 2726 'Thumbnail requires version > 3.2.0')
@@ -2684,7 +2738,7 @@ class Mastodon:
2684 # Wait for processing? 2738 # Wait for processing?
2685 if synchronous: 2739 if synchronous:
2686 if self.verify_minimum_version("3.1.4"): 2740 if self.verify_minimum_version("3.1.4"):
2687 while not "url" in ret_dict or ret_dict.url == None: 2741 while not "url" in ret_dict or ret_dict.url is None:
2688 try: 2742 try:
2689 ret_dict = self.media(ret_dict) 2743 ret_dict = self.media(ret_dict)
2690 time.sleep(1.0) 2744 time.sleep(1.0)
@@ -2707,13 +2761,13 @@ class Mastodon:
2707 """ 2761 """
2708 id = self.__unpack_id(id) 2762 id = self.__unpack_id(id)
2709 2763
2710 if focus != None: 2764 if focus is not None:
2711 focus = str(focus[0]) + "," + str(focus[1]) 2765 focus = str(focus[0]) + "," + str(focus[1])
2712 2766
2713 params = self.__generate_params( 2767 params = self.__generate_params(
2714 locals(), ['id', 'thumbnail', 'thumbnail_mime_type']) 2768 locals(), ['id', 'thumbnail', 'thumbnail_mime_type'])
2715 2769
2716 if not thumbnail is None: 2770 if thumbnail is not None:
2717 if not self.verify_minimum_version("3.2.0", cached=True): 2771 if not self.verify_minimum_version("3.2.0", cached=True):
2718 raise MastodonVersionError( 2772 raise MastodonVersionError(
2719 'Thumbnail requires version > 3.2.0') 2773 'Thumbnail requires version > 3.2.0')
@@ -2819,25 +2873,25 @@ class Mastodon:
2819 'policy': policy 2873 'policy': policy
2820 } 2874 }
2821 2875
2822 if follow_events != None: 2876 if follow_events is not None:
2823 params['data[alerts][follow]'] = follow_events 2877 params['data[alerts][follow]'] = follow_events
2824 2878
2825 if favourite_events != None: 2879 if favourite_events is not None:
2826 params['data[alerts][favourite]'] = favourite_events 2880 params['data[alerts][favourite]'] = favourite_events
2827 2881
2828 if reblog_events != None: 2882 if reblog_events is not None:
2829 params['data[alerts][reblog]'] = reblog_events 2883 params['data[alerts][reblog]'] = reblog_events
2830 2884
2831 if mention_events != None: 2885 if mention_events is not None:
2832 params['data[alerts][mention]'] = mention_events 2886 params['data[alerts][mention]'] = mention_events
2833 2887
2834 if poll_events != None: 2888 if poll_events is not None:
2835 params['data[alerts][poll]'] = poll_events 2889 params['data[alerts][poll]'] = poll_events
2836 2890
2837 if follow_request_events != None: 2891 if follow_request_events is not None:
2838 params['data[alerts][follow_request]'] = follow_request_events 2892 params['data[alerts][follow_request]'] = follow_request_events
2839 2893
2840 if follow_request_events != None: 2894 if follow_request_events is not None:
2841 params['data[alerts][status]'] = status_events 2895 params['data[alerts][status]'] = status_events
2842 2896
2843 # Canonicalize booleans 2897 # Canonicalize booleans
@@ -2857,22 +2911,22 @@ class Mastodon:
2857 """ 2911 """
2858 params = {} 2912 params = {}
2859 2913
2860 if follow_events != None: 2914 if follow_events is not None:
2861 params['data[alerts][follow]'] = follow_events 2915 params['data[alerts][follow]'] = follow_events
2862 2916
2863 if favourite_events != None: 2917 if favourite_events is not None:
2864 params['data[alerts][favourite]'] = favourite_events 2918 params['data[alerts][favourite]'] = favourite_events
2865 2919
2866 if reblog_events != None: 2920 if reblog_events is not None:
2867 params['data[alerts][reblog]'] = reblog_events 2921 params['data[alerts][reblog]'] = reblog_events
2868 2922
2869 if mention_events != None: 2923 if mention_events is not None:
2870 params['data[alerts][mention]'] = mention_events 2924 params['data[alerts][mention]'] = mention_events
2871 2925
2872 if poll_events != None: 2926 if poll_events is not None:
2873 params['data[alerts][poll]'] = poll_events 2927 params['data[alerts][poll]'] = poll_events
2874 2928
2875 if follow_request_events != None: 2929 if follow_request_events is not None:
2876 params['data[alerts][follow_request]'] = follow_request_events 2930 params['data[alerts][follow_request]'] = follow_request_events
2877 2931
2878 # Canonicalize booleans 2932 # Canonicalize booleans
@@ -2951,19 +3005,19 @@ class Mastodon:
2951 3005
2952 Returns a list of `admin account dicts`_. 3006 Returns a list of `admin account dicts`_.
2953 """ 3007 """
2954 if max_id != None: 3008 if max_id is not None:
2955 max_id = self.__unpack_id(max_id, dateconv=True) 3009 max_id = self.__unpack_id(max_id, dateconv=True)
2956 3010
2957 if min_id != None: 3011 if min_id is not None:
2958 min_id = self.__unpack_id(min_id, dateconv=True) 3012 min_id = self.__unpack_id(min_id, dateconv=True)
2959 3013
2960 if since_id != None: 3014 if since_id is not None:
2961 since_id = self.__unpack_id(since_id, dateconv=True) 3015 since_id = self.__unpack_id(since_id, dateconv=True)
2962 3016
2963 params = self.__generate_params( 3017 params = self.__generate_params(
2964 locals(), ['remote', 'status', 'staff_only']) 3018 locals(), ['remote', 'status', 'staff_only'])
2965 3019
2966 if remote == True: 3020 if remote:
2967 params["remote"] = True 3021 params["remote"] = True
2968 3022
2969 mod_statuses = ["active", "pending", 3023 mod_statuses = ["active", "pending",
@@ -2971,7 +3025,7 @@ class Mastodon:
2971 if not status in mod_statuses: 3025 if not status in mod_statuses:
2972 raise ValueError("Invalid moderation status requested.") 3026 raise ValueError("Invalid moderation status requested.")
2973 3027
2974 if staff_only == True: 3028 if staff_only:
2975 params["staff"] = True 3029 params["staff"] = True
2976 3030
2977 for mod_status in mod_statuses: 3031 for mod_status in mod_statuses:
@@ -3083,11 +3137,11 @@ class Mastodon:
3083 if action is None: 3137 if action is None:
3084 action = "none" 3138 action = "none"
3085 3139
3086 if send_email_notification == False: 3140 if not send_email_notification:
3087 send_email_notification = None 3141 send_email_notification = None
3088 3142
3089 id = self.__unpack_id(id) 3143 id = self.__unpack_id(id)
3090 if not report_id is None: 3144 if report_id is not None:
3091 report_id = self.__unpack_id(report_id) 3145 report_id = self.__unpack_id(report_id)
3092 3146
3093 params = self.__generate_params(locals(), ['id', 'action']) 3147 params = self.__generate_params(locals(), ['id', 'action'])
@@ -3107,22 +3161,22 @@ class Mastodon:
3107 3161
3108 Returns a list of `report dicts`_. 3162 Returns a list of `report dicts`_.
3109 """ 3163 """
3110 if max_id != None: 3164 if max_id is not None:
3111 max_id = self.__unpack_id(max_id, dateconv=True) 3165 max_id = self.__unpack_id(max_id, dateconv=True)
3112 3166
3113 if min_id != None: 3167 if min_id is not None:
3114 min_id = self.__unpack_id(min_id, dateconv=True) 3168 min_id = self.__unpack_id(min_id, dateconv=True)
3115 3169
3116 if since_id != None: 3170 if since_id is not None:
3117 since_id = self.__unpack_id(since_id, dateconv=True) 3171 since_id = self.__unpack_id(since_id, dateconv=True)
3118 3172
3119 if not account_id is None: 3173 if account_id is not None:
3120 account_id = self.__unpack_id(account_id) 3174 account_id = self.__unpack_id(account_id)
3121 3175
3122 if not target_account_id is None: 3176 if target_account_id is not None:
3123 target_account_id = self.__unpack_id(target_account_id) 3177 target_account_id = self.__unpack_id(target_account_id)
3124 3178
3125 if resolved == False: 3179 if not resolved:
3126 resolved = None 3180 resolved = None
3127 3181
3128 params = self.__generate_params(locals()) 3182 params = self.__generate_params(locals())
@@ -3279,12 +3333,12 @@ class Mastodon:
3279 # Figure out what size to decode to 3333 # Figure out what size to decode to
3280 decode_components_x, decode_components_y = blurhash.components( 3334 decode_components_x, decode_components_y = blurhash.components(
3281 media_dict["blurhash"]) 3335 media_dict["blurhash"])
3282 if size_per_component == False: 3336 if size_per_component:
3283 decode_size_x = out_size[0]
3284 decode_size_y = out_size[1]
3285 else:
3286 decode_size_x = decode_components_x * out_size[0] 3337 decode_size_x = decode_components_x * out_size[0]
3287 decode_size_y = decode_components_y * out_size[1] 3338 decode_size_y = decode_components_y * out_size[1]
3339 else:
3340 decode_size_x = out_size[0]
3341 decode_size_y = out_size[1]
3288 3342
3289 # Decode 3343 # Decode
3290 decoded_image = blurhash.decode( 3344 decoded_image = blurhash.decode(
@@ -3454,7 +3508,7 @@ class Mastodon:
3454 """ 3508 """
3455 Fetch the logged in user's ID, with caching. ID is reset on calls to log_in. 3509 Fetch the logged in user's ID, with caching. ID is reset on calls to log_in.
3456 """ 3510 """
3457 if self.__logged_in_id == None: 3511 if self.__logged_in_id is None:
3458 self.__logged_in_id = self.account_verify_credentials().id 3512 self.__logged_in_id = self.account_verify_credentials().id
3459 return self.__logged_in_id 3513 return self.__logged_in_id
3460 3514
@@ -3477,7 +3531,7 @@ class Mastodon:
3477 "updated_at", "last_status_at", "starts_at", "ends_at", "published_at", "edited_at"] 3531 "updated_at", "last_status_at", "starts_at", "ends_at", "published_at", "edited_at"]
3478 for k, v in json_object.items(): 3532 for k, v in json_object.items():
3479 if k in known_date_fields: 3533 if k in known_date_fields:
3480 if v != None: 3534 if v is not None:
3481 try: 3535 try:
3482 if isinstance(v, int): 3536 if isinstance(v, int):
3483 json_object[k] = datetime.datetime.fromtimestamp(v, pytz.utc) 3537 json_object[k] = datetime.datetime.fromtimestamp(v, pytz.utc)
@@ -3565,9 +3619,9 @@ class Mastodon:
3565 3619
3566 # Generate request headers 3620 # Generate request headers
3567 headers = copy.deepcopy(headers) 3621 headers = copy.deepcopy(headers)
3568 if not self.access_token is None: 3622 if self.access_token is not None:
3569 headers['Authorization'] = 'Bearer ' + self.access_token 3623 headers['Authorization'] = 'Bearer ' + self.access_token
3570 if not access_token_override is None: 3624 if access_token_override is not None:
3571 headers['Authorization'] = 'Bearer ' + access_token_override 3625 headers['Authorization'] = 'Bearer ' + access_token_override
3572 3626
3573 # Add user-agent 3627 # Add user-agent
@@ -3576,7 +3630,7 @@ class Mastodon:
3576 3630
3577 # Determine base URL 3631 # Determine base URL
3578 base_url = self.api_base_url 3632 base_url = self.api_base_url
3579 if not base_url_override is None: 3633 if base_url_override is not None:
3580 base_url = base_url_override 3634 base_url = base_url_override
3581 3635
3582 if self.debug_requests: 3636 if self.debug_requests:
@@ -3594,13 +3648,12 @@ class Mastodon:
3594 response_object = None 3648 response_object = None
3595 try: 3649 try:
3596 kwargs = dict(headers=headers, files=files, timeout=self.request_timeout) 3650 kwargs = dict(headers=headers, files=files, timeout=self.request_timeout)
3597 if use_json == False: 3651 if use_json:
3598 if method == 'GET':
3599 kwargs['params'] = params
3600 else:
3601 kwargs['data'] = params
3602 else:
3603 kwargs['json'] = params 3652 kwargs['json'] = params
3653 elif method == 'GET':
3654 kwargs['params'] = params
3655 else:
3656 kwargs['data'] = params
3604 3657
3605 # Block list with exactly three entries, matching on hashes of the instance API domain 3658 # Block list with exactly three entries, matching on hashes of the instance API domain
3606 # For more information, have a look at the docs 3659 # For more information, have a look at the docs
@@ -3636,7 +3689,7 @@ class Mastodon:
3636 ratelimit_intrep = None 3689 ratelimit_intrep = None
3637 3690
3638 try: 3691 try:
3639 if not ratelimit_intrep is None and ratelimit_intrep == response_object.headers['X-RateLimit-Reset']: 3692 if ratelimit_intrep is not None and ratelimit_intrep == response_object.headers['X-RateLimit-Reset']:
3640 self.ratelimit_reset = int( 3693 self.ratelimit_reset = int(
3641 response_object.headers['X-RateLimit-Reset']) 3694 response_object.headers['X-RateLimit-Reset'])
3642 else: 3695 else:
@@ -3689,7 +3742,7 @@ class Mastodon:
3689 request_complete = False 3742 request_complete = False
3690 continue 3743 continue
3691 3744
3692 if skip_error_check == False: 3745 if not skip_error_check:
3693 if response_object.status_code == 404: 3746 if response_object.status_code == 404:
3694 ex_type = MastodonNotFoundError 3747 ex_type = MastodonNotFoundError
3695 if not error_msg: 3748 if not error_msg:
@@ -3718,7 +3771,7 @@ class Mastodon:
3718 if return_response_object: 3771 if return_response_object:
3719 return response_object 3772 return response_object
3720 3773
3721 if parse == True: 3774 if parse:
3722 try: 3775 try:
3723 response = response_object.json( 3776 response = response_object.json(
3724 object_hook=self.__json_hooks) 3777 object_hook=self.__json_hooks)
@@ -3881,7 +3934,7 @@ class Mastodon:
3881 3934
3882 def close(self): 3935 def close(self):
3883 self.closed = True 3936 self.closed = True
3884 if not self.connection is None: 3937 if self.connection is not None:
3885 self.connection.close() 3938 self.connection.close()
3886 3939
3887 def is_alive(self): 3940 def is_alive(self):
@@ -3907,7 +3960,7 @@ class Mastodon:
3907 3960
3908 # Run until closed or until error if not autoreconnecting 3961 # Run until closed or until error if not autoreconnecting
3909 while self.running: 3962 while self.running:
3910 if not self.connection is None: 3963 if self.connection is not None:
3911 with closing(self.connection) as r: 3964 with closing(self.connection) as r:
3912 try: 3965 try:
3913 listener.handle_stream(r) 3966 listener.handle_stream(r)
@@ -3978,10 +4031,8 @@ class Mastodon:
3978 4031
3979 param_keys = list(params.keys()) 4032 param_keys = list(params.keys())
3980 for key in param_keys: 4033 for key in param_keys:
3981 if isinstance(params[key], bool) and params[key] == False: 4034 if isinstance(params[key], bool):
3982 params[key] = '0' 4035 params[key] = '1' if params[key] else '0'
3983 if isinstance(params[key], bool) and params[key] == True:
3984 params[key] = '1'
3985 4036
3986 for key in param_keys: 4037 for key in param_keys:
3987 if params[key] is None or key in exclude: 4038 if params[key] is None or key in exclude:
diff --git a/mastodon/streaming.py b/mastodon/streaming.py
index e43d7d6..ed09705 100644
--- a/mastodon/streaming.py
+++ b/mastodon/streaming.py
@@ -22,18 +22,50 @@ class StreamListener(object):
22 Mastodon.hashtag_stream().""" 22 Mastodon.hashtag_stream()."""
23 23
24 def on_update(self, status): 24 def on_update(self, status):
25 """A new status has appeared. 'status' is the parsed JSON dictionary 25 """A new status has appeared. `status` is the parsed `status dict`
26 describing the status.""" 26 describing the status."""
27 pass 27 pass
28 28
29 def on_delete(self, status_id):
30 """A status has been deleted. `status_id` is the status' integer ID."""
31 pass
32
33 def on_notification(self, notification):
34 """A new notification. `notification` is the parsed `notification dict`
35 describing the notification."""
36 pass
37
38 def on_filters_changed(self):
39 """Filters have changed. Does not contain a payload, you will have to
40 refetch filters yourself."""
41 pass
42
43 def on_conversation(self, conversation):
44 """A direct message (in the direct stream) has been received. `conversation`
45 is the parsed `conversation dict` dictionary describing the conversation"""
46 pass
47
48 def on_announcement(self, annoucement):
49 """A new announcement has been published. `announcement` is the parsed
50 `announcement dict` describing the newly posted announcement."""
51 pass
52
53 def on_announcement_reaction(self, TODO):
54 """Someone has reacted to an announcement. TODO: what is payload lol"""
55 pass
56
57 def on_announcement_delete(self, annoucement_id):
58 """An announcement has been deleted. `annoucement_id` is the id of the
59 deleted announcement."""
60 pass
61
29 def on_status_update(self, status): 62 def on_status_update(self, status):
30 """A status has been edited. 'status' is the parsed JSON dictionary 63 """A status has been edited. 'status' is the parsed JSON dictionary
31 describing the updated status.""" 64 describing the updated status."""
32 pass 65 pass
33 66
34 def on_notification(self, notification): 67 def on_encrypted_message(self, unclear):
35 """A new notification. 'notification' is the parsed JSON dictionary 68 """An encrypted message has been received. Currently unused."""
36 describing the notification."""
37 pass 69 pass
38 70
39 def on_abort(self, err): 71 def on_abort(self, err):
@@ -47,15 +79,6 @@ class StreamListener(object):
47 """ 79 """
48 pass 80 pass
49 81
50 def on_delete(self, status_id):
51 """A status has been deleted. status_id is the status' integer ID."""
52 pass
53
54 def on_conversation(self, conversation):
55 """A direct message (in the direct stream) has been received. conversation
56 contains the resulting conversation dict."""
57 pass
58
59 def on_unknown_event(self, name, unknown_event=None): 82 def on_unknown_event(self, name, unknown_event=None):
60 """An unknown mastodon API event has been received. The name contains the event-name and unknown_event 83 """An unknown mastodon API event has been received. The name contains the event-name and unknown_event
61 contains the content of the unknown event. 84 contains the content of the unknown event.
@@ -148,8 +171,7 @@ class StreamListener(object):
148 for_stream = json.loads(event['stream']) 171 for_stream = json.loads(event['stream'])
149 except: 172 except:
150 for_stream = None 173 for_stream = None
151 payload = json.loads( 174 payload = json.loads(data, object_hook=Mastodon._Mastodon__json_hooks)
152 data, object_hook=Mastodon._Mastodon__json_hooks)
153 except KeyError as err: 175 except KeyError as err:
154 exception = MastodonMalformedEventError( 176 exception = MastodonMalformedEventError(
155 'Missing field', err.args[0], event) 177 'Missing field', err.args[0], event)
@@ -188,11 +210,13 @@ class StreamListener(object):
188 handler(name, payload, for_stream) 210 handler(name, payload, for_stream)
189 else: 211 else:
190 if handler != self.on_unknown_event: 212 if handler != self.on_unknown_event:
191 handler(payload) 213 if handler == self.on_filters_changed:
214 handler()
215 else:
216 handler(payload)
192 else: 217 else:
193 handler(name, payload) 218 handler(name, payload)
194 219
195
196class CallbackStreamListener(StreamListener): 220class CallbackStreamListener(StreamListener):
197 """ 221 """
198 Simple callback stream handler class. 222 Simple callback stream handler class.
@@ -202,22 +226,41 @@ class CallbackStreamListener(StreamListener):
202 for diagnostics. 226 for diagnostics.
203 """ 227 """
204 228
205 def __init__(self, update_handler=None, local_update_handler=None, delete_handler=None, notification_handler=None, conversation_handler=None, unknown_event_handler=None, status_update_handler=None): 229 def __init__(self,
230 update_handler=None,
231 local_update_handler=None,
232 delete_handler=None,
233 notification_handler=None,
234 conversation_handler=None,
235 unknown_event_handler=None,
236 status_update_handler=None,
237 filters_changed_handler=None,
238 announcement_handler=None,
239 announcement_reaction_handler=None,
240 announcement_delete_handler=None,
241 encryted_message_handler=None
242
243 ):
206 super(CallbackStreamListener, self).__init__() 244 super(CallbackStreamListener, self).__init__()
207 self.update_handler = update_handler 245 self.update_handler = update_handler
208 self.local_update_handler = local_update_handler 246 self.local_update_handler = local_update_handler
209 self.delete_handler = delete_handler 247 self.delete_handler = delete_handler
210 self.notification_handler = notification_handler 248 self.notification_handler = notification_handler
249 self.filters_changed_handler = filters_changed_handler
211 self.conversation_handler = conversation_handler 250 self.conversation_handler = conversation_handler
212 self.unknown_event_handler = unknown_event_handler 251 self.unknown_event_handler = unknown_event_handler
213 self.status_update_handler = status_update_handler 252 self.status_update_handler = status_update_handler
253 self.announcement_handler = announcement_handler
254 self.announcement_reaction_handler = announcement_reaction_handler
255 self.announcement_delete_handler = announcement_delete_handler
256 self.encryted_message_handler = encryted_message_handler
214 257
215 def on_update(self, status): 258 def on_update(self, status):
216 if self.update_handler != None: 259 if self.update_handler is not None:
217 self.update_handler(status) 260 self.update_handler(status)
218 261
219 try: 262 try:
220 if self.local_update_handler != None and not "@" in status["account"]["acct"]: 263 if self.local_update_handler is not None and not "@" in status["account"]["acct"]:
221 self.local_update_handler(status) 264 self.local_update_handler(status)
222 except Exception as err: 265 except Exception as err:
223 six.raise_from( 266 six.raise_from(
@@ -226,21 +269,41 @@ class CallbackStreamListener(StreamListener):
226 ) 269 )
227 270
228 def on_delete(self, deleted_id): 271 def on_delete(self, deleted_id):
229 if self.delete_handler != None: 272 if self.delete_handler is not None:
230 self.delete_handler(deleted_id) 273 self.delete_handler(deleted_id)
231 274
232 def on_notification(self, notification): 275 def on_notification(self, notification):
233 if self.notification_handler != None: 276 if self.notification_handler is not None:
234 self.notification_handler(notification) 277 self.notification_handler(notification)
235 278
279 def on_filters_changed(self):
280 if self.filters_changed_handler is not None:
281 self.filters_changed_handler()
282
236 def on_conversation(self, conversation): 283 def on_conversation(self, conversation):
237 if self.conversation_handler != None: 284 if self.conversation_handler is not None:
238 self.conversation_handler(conversation) 285 self.conversation_handler(conversation)
239 286
240 def on_unknown_event(self, name, unknown_event=None): 287 def on_announcement(self, annoucement):
241 if self.unknown_event_handler != None: 288 if self.announcement_handler is not None:
242 self.unknown_event_handler(name, unknown_event) 289 self.announcement_handler(annoucement)
290
291 def on_announcement_reaction(self, TODO):
292 if self.announcement_reaction_handler is not None:
293 self.announcement_reaction_handler(TODO)
294
295 def on_announcement_delete(self, annoucement_id):
296 if self.announcement_delete_handler is not None:
297 self.announcement_delete_handler(annoucement_id)
243 298
244 def on_status_update(self, status): 299 def on_status_update(self, status):
245 if self.status_update_handler != None: 300 if self.status_update_handler is not None:
246 self.status_update_handler(status) 301 self.status_update_handler(status)
302
303 def on_encrypted_message(self, unclear):
304 if self.encryted_message_handler is not None:
305 self.encryted_message_handler(unclear)
306
307 def on_unknown_event(self, name, unknown_event=None):
308 if self.unknown_event_handler is not None:
309 self.unknown_event_handler(name, unknown_event) \ No newline at end of file
Powered by cgit v1.2.3 (git 2.41.0)