diff --git a/docs/supportedsites.md b/docs/supportedsites.md
index 1432c5ca..d0f3fdce 100644
--- a/docs/supportedsites.md
+++ b/docs/supportedsites.md
@@ -268,7 +268,7 @@ Consider all listed sites to potentially be NSFW.
| Discord |
https://discord.com/ |
- Channels, DMs, Messages, Servers, Server Assets |
+ Channels, DMs, Messages, Servers, Server Assets, Server Searches |
|
diff --git a/gallery_dl/extractor/discord.py b/gallery_dl/extractor/discord.py
index 576b0cc2..77267149 100644
--- a/gallery_dl/extractor/discord.py
+++ b/gallery_dl/extractor/discord.py
@@ -126,6 +126,14 @@ class DiscordExtractor(Extractor):
message_metadata_file.update(file)
yield Message.Url, file["url"], message_metadata_file
+ def extract_search(self, server_id, params):
+ for messages in self.api.get_search_messages(server_id, params):
+ for message in messages:
+ if message["channel_id"] not in self.server_channels_metadata:
+ self.parse_channel(self.api.get_channel(
+ message["channel_id"]))
+ yield from self.extract_message(message)
+
def extract_channel_text(self, channel_id):
for message in self.api.get_channel_messages(channel_id):
yield from self.extract_message(message)
@@ -312,6 +320,30 @@ class DiscordServerAssetsExtractor(DiscordExtractor):
yield Message.Url, asset["url"], asset
+class DiscordServerSearchExtractor(DiscordExtractor):
+ subcategory = "server-search"
+ pattern = BASE_PATTERN + r"/channels/(\d+)/search/?\?([^#]+)"
+ example = "https://discord.com/channels/1234567890/search?QUERY"
+
+ def items(self):
+ server_id, query = self.groups
+ server = self.api.get_server(server_id)
+ self.kwdict.update(self.parse_server(server))
+
+ params = {
+ **text.parse_query_list(query, {
+ "from", "in", "has", "mentions", "author_id", "channel_id"}),
+ "sort_by" : "timestamp",
+ "sort_order": "desc",
+ }
+ if "from" in params:
+ params["author_id"] = params.pop("from")
+ if "in" in params:
+ params["channel_id"] = params.pop("in")
+
+ return self.extract_search(server_id, params)
+
+
class DiscordServerExtractor(DiscordExtractor):
subcategory = "server"
pattern = BASE_PATTERN + r"/channels/(\d+)/?$"
@@ -410,6 +442,17 @@ class DiscordAPI():
return self._pagination(_method, MESSAGES_BATCH)
+ def get_search_messages(self, server_id, params):
+ """Get search messages"""
+ MESSAGES_BATCH = 25
+
+ def _method(offset):
+ params["offset"] = offset
+ return self._call(url, params)["messages"]
+
+ url = f"/guilds/{server_id}/messages/search"
+ return self._pagination(_method, MESSAGES_BATCH)
+
def get_message(self, channel_id, message_id):
"""Get message information"""
return self._call("/channels/" + channel_id + "/messages", {
diff --git a/test/results/discord.py b/test/results/discord.py
index 1d9d9db4..d21c7d87 100644
--- a/test/results/discord.py
+++ b/test/results/discord.py
@@ -107,4 +107,14 @@ __tests__ = (
"url" : str,
},
+{
+ "#url" : "https://discord.com/channels/1067148002722062416/search?from=429235270664060948",
+ "#class" : discord.DiscordServerSearchExtractor,
+},
+
+{
+ "#url" : "https://discord.com/channels/1067148002722062416/search?has=file&has=link&mentions=429235270664060948",
+ "#class" : discord.DiscordServerSearchExtractor,
+},
+
)