├── .gitignore
├── .env.example
├── .cargo
└── config
├── .gitattributes
├── requirements.txt
├── .idea
├── vcs.xml
├── .gitignore
├── discord.xml
├── modules.xml
└── whats-that-song.iml
├── Cargo.toml
├── README.md
├── LICENSE.md
├── api.py
├── src
└── main.rs
└── Cargo.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | tmp/
3 | .env
4 | token.txt
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | DISCORD_TOKEN=
2 | API_SERVER=http://localhost:6799
--------------------------------------------------------------------------------
/.cargo/config:
--------------------------------------------------------------------------------
1 | [build]
2 | rustflags = ["-C", "target-cpu=native"]
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | shazamio
2 | discord
3 | aiohttp
4 | yt_dlp
5 | flask
6 | flask[async]
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/discord.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/whats-that-song.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "whats-that-song"
3 | authors = ["dangered wolf"]
4 | license = "MIT"
5 | version = "2.0.0"
6 | edition = "2021"
7 |
8 | [dependencies]
9 | tokio = { version = "1", features = ["full"] }
10 | dotenv = "0.15.0"
11 | lazy_static = "1.4.0"
12 | regex = "1.6.0"
13 | rand = "0.8.5"
14 | reqwest = { version = "0.11.11", features = [ "json" ] }
15 | serde = { version = "1.0", features = [ "derive" ] }
16 | mime_guess = "2.0.4"
17 | urlencoding = "2.1.2"
18 |
19 | [dependencies.serenity]
20 | version = "0.11"
21 | default-features = false
22 | features = [
23 | "builder",
24 | "cache",
25 | "chrono",
26 | "client",
27 | "gateway",
28 | "model",
29 | "http",
30 | "utils",
31 | "rustls_backend",
32 | "unstable_discord_api",
33 | ]
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | What's That Song?
2 | ==
3 |
4 | A Discord bot that finds the song given a video or audio file, using Shazam.
5 |
6 | Bot written in Rust with Serenity. Interfaces with an internal API written in Python that connects to ShazamIO and yt-dlp.
7 |
8 | ## Quick start
9 |
10 | 1. Install Python 3.8 or later (3.10 recommended) and FFmpeg, and Rust toolchain
11 | 2. Install the Python API requirements with `pip install -r requirements.txt`
12 | 3. Put bot token in `.env`
13 | 4. Run `api.py`
14 | 5. `cargo build --release && target/release/whats-that-song`
15 | 6. Profit
16 |
17 | ## Limitations
18 |
19 | We extract only the first minute of audio out of an audio clip. If music occurs later on in a video or audio clip, it will not be recognized.
20 |
21 | Active live streams, and videos longer than 30 minutes, will not be processed using yt-dlp extractor. This is to help keep response times low.
22 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 dangered wolf
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/api.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import mimetypes
3 | import os
4 | import random
5 | import time
6 | import aiohttp
7 | import flask
8 | import yt_dlp as yt
9 | from shazamio import Shazam
10 | from urllib.parse import urlparse
11 |
12 | # Make ./tmp if it does not already exist
13 | if not os.path.exists("./tmp"):
14 | os.mkdir("./tmp")
15 |
16 | # Delete all files in ./tmp on startup
17 | for file in os.listdir("./tmp"):
18 | os.remove("./tmp/" + file)
19 |
20 | def ytdl_filter(info):
21 | # print json conversion of info
22 | if (info.get("is_live")):
23 | return "WTS cannot process currently live streams"
24 | if (info.get("duration") > 3600): # 60 minutes
25 | return "WTS cannot process videos longer than 60 minutes"
26 |
27 | return None
28 |
29 | headers = {
30 | "sec-ch-ua": '".Not/A)Brand";v="99", "Google Chrome";v="104", "Chromium";v="104"',
31 | "DNT": '1',
32 | "sec-ch-ua-mobile": '?0',
33 | "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36',
34 | "sec-ch-ua-platform": '"Windows"',
35 | "Accept": '*/*',
36 | "Sec-Fetch-Site": 'none',
37 | "Sec-Fetch-Mode": 'no-cors',
38 | "Accept-Encoding": 'gzip, deflate, br',
39 | "Accept-Language": 'en',
40 | "Cache-Control": 'no-cache',
41 | "Pragma": 'no-cache',
42 | "Upgrade-Insecure-Requests": '1',
43 | }
44 | mimetypes.init()
45 | shazam = Shazam()
46 |
47 | # Create YouTube-Dl but disallow live streams
48 | ytdl = yt.YoutubeDL({ "format" : "worstaudio/worst", "outtmpl": "tmp/%(id)s.%(ext)s", "postprocessors": [{ "key": "FFmpegExtractAudio", "preferredcodec": "aac", "nopostoverwrites": True }], "noplaylist": True, "match_filter": ytdl_filter })
49 |
50 | app = flask.Flask("whatsthatsong")
51 |
52 | # Twitter fetch API with Tweet ID
53 | @app.route("/twitter/")
54 | async def twitter_engine(tweet_id):
55 | async with aiohttp.ClientSession() as session:
56 | async with session.get(f"https://api.fxtwitter.com/status/{tweet_id}", headers=headers) as resp:
57 | data = await resp.json()
58 | tweet = data.get("tweet")
59 | if tweet is None:
60 | return None
61 | media = tweet.get("media")
62 | if media is None:
63 | return None
64 | videos = media.get("videos")
65 | if videos is None:
66 | return None
67 | video = videos[0]
68 | if video is None:
69 | return None
70 | video_url = video.get("url")
71 | print("video_url", video_url)
72 | if video_url is None:
73 | return None
74 | return await process_video(video_url)
75 |
76 | @app.route("/ytdl")
77 | async def ytdl_engine():
78 | url = urlparse(flask.request.args.get("url")).geturl()
79 | if url is None:
80 | return "No URL provided", 400
81 | print(f"Processing {url} with ytdl")
82 | filepath = None
83 | try:
84 | info = ytdl.extract_info(url)
85 | if info.get("requested_downloads") is not None and info.get("requested_downloads")[0] is not None:
86 | download = info.get("requested_downloads")[0]
87 | filepath = download.get("filepath")
88 | print(f"Requested download: {download}")
89 | print(f"File path: {filepath}")
90 | out = await shazam.recognize_song(filepath)
91 | os.remove(filepath)
92 | return out
93 | except Exception as e:
94 | print(e)
95 | try:
96 | os.remove(filepath)
97 | except:
98 | pass
99 | raise e
100 |
101 | @app.route("/direct")
102 | async def direct_engine():
103 | url = urlparse(flask.request.args.get("url")).geturl()
104 | if url is None:
105 | return "No URL provided", 400
106 | print(f"Processing {url} with direct")
107 | return await process_video(url)
108 |
109 | async def process_video(url):
110 | print(f"Processing {url} with direct video")
111 | randomname = str(random.randint(0, 2147483647))
112 | randomoutput = str(random.randint(0, 2147483647))
113 |
114 | async with aiohttp.ClientSession() as session:
115 | # TODO: use media-proxy.dangeredwolf.com for non-Discord URLs
116 | async with session.get(url, headers=headers) as resp:
117 | print(f"Response status code: {str(resp.status)}")
118 | filename = "./tmp/" + randomname
119 | audiofilename = "./tmp/" + randomoutput + ".aac"
120 | with open(filename, 'wb') as f:
121 | while True:
122 | chunk = await resp.content.read(1024)
123 | if not chunk:
124 | break
125 | f.write(chunk)
126 | try:
127 | print(f"Extracting audio from {url}")
128 | # Call system ffmpeg to convert to aac
129 | os.system(f"ffmpeg -i {filename} -t 180 -vn -acodec aac {audiofilename}")
130 | os.remove(filename)
131 | print(f"Finding music in {url}")
132 | out = await shazam.recognize_song(audiofilename)
133 | print(f"Music lookup finished for {url}")
134 | os.remove(audiofilename)
135 | # shazamio's serializer is useless and returns None for stuff like album art for no reason, so it's unusable
136 | return out
137 | except Exception as e:
138 | print(e)
139 | try:
140 | os.remove(filename)
141 | except:
142 | pass
143 | try:
144 | os.remove(audiofilename)
145 | except:
146 | pass
147 | raise e
148 |
149 | token = None
150 | token_expires = 0
151 |
152 | async def get_spotify_token():
153 |
154 | global token
155 | global token_expires
156 | # Compare current time ms to token_expires
157 | if (token_expires > time.time() * 1000):
158 | print("We already have a hopefully valid token")
159 | return token
160 | async with aiohttp.ClientSession() as session:
161 | async with session.get("https://open.spotify.com/get_access_token?reason=transport&productType=web-player", headers=headers) as resp:
162 | # If we get a 200, we have a valid token
163 | if resp.status == 200:
164 | data = await resp.json()
165 | token = data.get("accessToken")
166 | token_expires = data.get("accessTokenExpirationTimestampMs")
167 | return token
168 | elif resp.status == 429:
169 | print("We got rate limited, gimme a sec")
170 | await asyncio.sleep(1)
171 | return await get_spotify_token()
172 |
173 | @app.route("/spotify")
174 | async def spotify_search():
175 | song = flask.request.args.get("song")
176 | artist = flask.request.args.get("artist")
177 | if song is None:
178 | return "No song provided", 400
179 | if artist is None:
180 | return "No artist provided", 400
181 | query = song + " " + artist
182 | print(f"Searching Spotify for {query}")
183 | token = await get_spotify_token()
184 | async with aiohttp.ClientSession() as session:
185 | async with session.get(f"https://api.spotify.com/v1/search?q={query}&type=track&limit=1", headers={**headers, "Authorization": f"Bearer {token}"}) as resp:
186 | if resp.status == 200:
187 | data = await resp.json()
188 | tracks = data.get("tracks")
189 | if tracks is None:
190 | print("Check failed: tracks is None")
191 | return "", 404
192 | items = tracks.get("items")
193 | if items is None:
194 | print("Check failed: items is None")
195 | return "", 404
196 | item = items[0]
197 | if item is None:
198 | print("Check failed: item[0] is None")
199 | return "", 404
200 | # Check through artists to make sure original artist is in the list
201 | artists = item.get("artists")
202 | if artists is None:
203 | print("Check failed: artists is None")
204 | return "", 404
205 | matched_artist = False
206 | for artistI in artists:
207 | # We have some leniency here because Spotify might include extra things like (feat. etc)
208 | if artist.lower() in artistI.get("name").lower() or artistI.get("name").lower() in artist.lower():
209 | print("Matched artist")
210 | matched_artist = True
211 | break
212 | if not matched_artist:
213 | print("Check failed: No matching artist")
214 | return "", 404
215 | matched_song = False
216 | for songI in items:
217 | # We have some leniency here because Spotify might include extra things like (feat. etc)
218 | if song.lower() in songI.get("name").lower() or songI.get("name").lower() in song.lower():
219 | print("Matched song")
220 | matched_song = True
221 | break
222 | if not matched_song:
223 | print("Check failed: No matching song title")
224 | return "", 404
225 | resp = flask.Response(item.get("external_urls").get("spotify") + "?si")
226 | resp.headers['Content-Type'] = 'text/plain'
227 | return resp
228 | elif resp.status == 429:
229 | print("We got rate limited, let's try another token")
230 | token = await get_spotify_token()
231 | return await spotify_search()
232 |
233 | # start server
234 | app.run(host="localhost", port=6799)
--------------------------------------------------------------------------------
/src/main.rs:
--------------------------------------------------------------------------------
1 | use std::env;
2 | use std::time::Duration;
3 | use lazy_static::lazy_static;
4 | use regex::Regex;
5 | use rand::seq::SliceRandom;
6 |
7 | use dotenv;
8 | use mime_guess::{self, mime};
9 | use urlencoding::encode;
10 | use serde::Deserialize;
11 |
12 | use serenity::async_trait;
13 | use serenity::model::prelude::component::{ButtonStyle};
14 | use serenity::model::prelude::{Activity, ReactionType};
15 | use serenity::model::prelude::interaction::{MessageFlags};
16 | use serenity::model::application::interaction::Interaction;
17 | use serenity::model::application::interaction::InteractionResponseType;
18 | use serenity::utils::Colour;
19 | use serenity::model::gateway::Ready;
20 | use serenity::prelude::*;
21 | use tokio::time::sleep;
22 |
23 | extern crate reqwest;
24 |
25 | #[derive(Deserialize)]
26 | struct ShazamAction {
27 | uri: String
28 | }
29 |
30 | #[derive(Deserialize)]
31 | struct ShazamMetadata {
32 | text: String,
33 | title: String
34 | }
35 |
36 | #[derive(Deserialize)]
37 | struct ShazamSection {
38 | metadata: Option>
39 | }
40 |
41 | #[derive(Deserialize)]
42 | struct ShazamProvider {
43 | #[serde(rename = "type")]
44 | provider_type: String,
45 | providername: Option,
46 | actions: Vec
47 | }
48 |
49 | #[derive(Deserialize)]
50 | struct ShazamHub {
51 | providers: Vec,
52 | options: Vec
53 | }
54 |
55 | #[derive(Deserialize)]
56 | struct ShazamImages {
57 | // background: String,
58 | // coverart: String,
59 | coverarthq: String
60 | }
61 |
62 | #[derive(Deserialize)]
63 | struct ShazamTrack {
64 | title: String,
65 | subtitle: String,
66 | url: String,
67 | images: Option,
68 | sections: Vec,
69 | hub: ShazamHub
70 | }
71 |
72 | #[derive(Deserialize)]
73 | struct ShazamResponse {
74 | timestamp: Option,
75 | track: Option,
76 | }
77 |
78 | struct ShazamProviderList {
79 | spotify: Option,
80 | apple: Option,
81 | deezer: Option,
82 | }
83 |
84 | struct SpotifyResponse {
85 | url: Option
86 | }
87 |
88 | struct Handler;
89 |
90 | lazy_static! {
91 | static ref TWITTER_LINK_REGEX: Regex = Regex::new(
92 | r"(?i)https?://((fx|px|vx)?twitter|twxtter|twittpr|twitter64)\.com/\w{1,15}/status(es)?/\d+"
93 | ).unwrap();
94 | static ref LINK_REGEX: Regex = Regex::new(
95 | r"(?i)https?://\S+"
96 | ).unwrap();
97 | static ref CLIENT: reqwest::Client = reqwest::Client::new();
98 |
99 | static ref RANDOM_MESSAGES: Vec = vec![
100 | "I found it!".to_string(),
101 | "This might be the song you're looking for.".to_string(),
102 | "I hope this helps.".to_string(),
103 | "Hey, I love this song too.".to_string(),
104 | "I like your taste.".to_string(),
105 | "I was wondering about this song too.".to_string(),
106 | ];
107 | }
108 |
109 | async fn fetch_url(url: &str) -> ShazamResponse {
110 | let api_server = dotenv::var("API_SERVER").unwrap();
111 | let url = format!("{}{}", api_server, url);
112 | let data = match CLIENT.get(url).send().await {
113 | Ok(data) => {
114 | // Check if the status is successful
115 | if data.status().is_success() {
116 | data.json::().await.unwrap()
117 | } else {
118 | return ShazamResponse {
119 | timestamp: None,
120 | track: None
121 | }
122 | }
123 | },
124 | Err(err) => {
125 | panic!("API request failed: {:?}", err);
126 | }
127 | };
128 | return data;
129 | }
130 |
131 | async fn fetch_spotify(artist: &str, song: &str) -> SpotifyResponse {
132 | let api_server = dotenv::var("API_SERVER").unwrap();
133 | let url = &format!("{}/spotify?artist={}&song={}", api_server, encode(artist), encode(song));
134 | match CLIENT.get(url).send().await {
135 | Ok(data) => {
136 | // Check if the status is successful
137 | if data.status().is_success() {
138 | return SpotifyResponse {
139 | url: Some(data.text().await.unwrap().to_string())
140 | }
141 | } else {
142 | return SpotifyResponse {
143 | url: None
144 | }
145 | }
146 | },
147 | Err(err) => {
148 | panic!("Spotify request failed: {:?}", err);
149 | }
150 | };
151 | }
152 |
153 | async fn fetch_direct(url: &str) -> ShazamResponse {
154 | let url = &format!("/direct?url={}", encode(url));
155 | return fetch_url(&url).await;
156 | }
157 |
158 | async fn fetch_twitter(url: &str) -> ShazamResponse {
159 | let id = url.split('/').last().unwrap();
160 | let url = &format!("/twitter/{}", id);
161 | return fetch_url(&url).await;
162 | }
163 |
164 | async fn fetch_ytdl(url: &str) -> ShazamResponse {
165 | let url = &format!("/ytdl?url={}", encode(url));
166 | return fetch_url(&url).await;
167 | }
168 |
169 | fn should_direct_download(url: &str) -> bool {
170 | // Checks the URL and sees if it looks like a video or audio file (mp3, mp4, etc.)
171 | let url = url.to_lowercase();
172 | let _guess = mime_guess::from_path(url).first();
173 | if _guess.is_none() {
174 | return false;
175 | }
176 | let guess = _guess.unwrap();
177 | let content_type = guess.type_();
178 | if content_type == mime::VIDEO || content_type == mime::AUDIO {
179 | return true;
180 | } else {
181 | return false;
182 | }
183 | }
184 |
185 | fn matches_twitter_link(url: &str) -> bool {
186 | return TWITTER_LINK_REGEX.is_match(url);
187 | }
188 |
189 | async fn handle_response(ctx: Context, msg: &serenity::model::channel::Message, data: ShazamResponse, interaction: Option) {
190 | let mut error_embed = serenity::builder::CreateEmbed::default();
191 | let track = match data.track {
192 | Some(track) => track,
193 | None => {
194 | // If timestamp exists, then reply with no matches, otherwise return an error
195 | match data.timestamp {
196 | Some(_) => {
197 | error_embed.title("No matches found")
198 | .description("We searched your media for a matching song, and couldn't find anything.\n\n**What are common causes for this?**\n• There is no music in the first few minutes of the media (we can only send so much data to Shazam)\n• Loud voiceovers can make it harder to recognize music\n• The song is not in Shazam's database")
199 | .color(Colour::ORANGE);
200 | },
201 | None => {
202 | error_embed.title("Failed to process media")
203 | .description("We tried processing the media you requested, but an error occurred somewhere along the way. Sorry about that.\n\n**What are common causes for this?**\n• You tried processing media longer than 1 hour\n• You tried processing a currently active live stream\n• You uploaded a corrupt media file, or one not supported by FFmpeg.")
204 | .color(Colour::RED);
205 | }
206 | }
207 | if interaction.is_some() {
208 | // Send as an followup message
209 | if let Interaction::ApplicationCommand(command) = interaction.unwrap() {
210 | command.create_followup_message(&ctx.http, |f| {
211 | f.embed(|e| {
212 | e.0 = error_embed.0;
213 | e
214 | })
215 | }).await.unwrap();
216 | }
217 |
218 | } else {
219 | if let Err(why) = msg.channel_id.send_message(&ctx.http, |m|
220 | m.embed(|e| {
221 | e.0 = error_embed.0;
222 | e
223 | })
224 | .reference_message(msg)
225 | ).await {
226 | println!("Error sending message: {:?}", why);
227 | }
228 | }
229 | return;
230 | }
231 | };
232 | println!("Found track: {}", track.title);
233 | let title = track.title;
234 | let artist = track.subtitle;
235 | let url = track.url;
236 |
237 | let spotify = fetch_spotify(&artist, &title).await;
238 |
239 | // Set message to a random string from RANDOM_MESSAGES
240 | let message = RANDOM_MESSAGES.choose(&mut rand::thread_rng()).unwrap().to_string();
241 |
242 | // Get the metadata from the track's section 0
243 |
244 | let mut embed = serenity::builder::CreateEmbed::default();
245 | embed.title(&title)
246 | .description(&artist)
247 | .url(&url)
248 | .color(Colour::BLUE)
249 | .footer(|f| f.text("Shazam").icon_url("https://cdn.discordapp.com/attachments/165560751363325952/1014753423045955674/84px-Shazam_icon.svg1.png"));
250 |
251 | // If we have images, then set coverart to the coverarthq
252 | if track.images.is_some() {
253 | let images = track.images.unwrap();
254 | let coverarthq = images.coverarthq.as_str();
255 | embed.thumbnail(&coverarthq);
256 | }
257 |
258 | // make new ShazamProviderList
259 | let mut providers = ShazamProviderList {
260 | spotify: None,
261 | apple: None,
262 | deezer: None,
263 | };
264 | for provider in track.hub.providers {
265 | println!("Found provider: {}", provider.provider_type);
266 | match provider.provider_type.as_str() {
267 | "SPOTIFY" => {
268 | providers.spotify = Some(provider);
269 | },
270 | "DEEZER" => {
271 | providers.deezer = Some(provider);
272 | },
273 | _ => {}
274 | }
275 | }
276 | for option in track.hub.options {
277 | if option.providername.is_some() {
278 | match option.providername.clone().unwrap().as_str() {
279 | "applemusic" => {
280 | let url = option.actions[0].uri.clone();
281 | // Occurs if the song was not found on Apple Music
282 | if url.starts_with("https://music.apple.com/subscribe") {
283 | continue;
284 | }
285 |
286 | providers.apple = Some(option);
287 | },
288 | _ => {}
289 | }
290 | }
291 | }
292 |
293 | let mut buttons: Vec = Vec::new();
294 |
295 | // Iterate through providers and add them to the embed
296 | if spotify.url.is_some() {
297 | // if providers.spotify.is_some() {
298 | // let provider = providers.spotify.unwrap();
299 | // let url = provider.actions[0].uri.clone().replace("spotify:search:", "https://open.spotify.com/search/");
300 | let mut button = serenity::builder::CreateButton::default();
301 | let emoji = ReactionType::try_from("<:Spotify:1014768475593506836>").unwrap();
302 |
303 | // if spotify.url.is_some() {
304 | let url = spotify.url.unwrap();
305 | // }
306 |
307 | button.label("Spotify")
308 | .style(ButtonStyle::Link)
309 | .url(&url)
310 | .emoji(emoji);
311 | buttons.push(button);
312 | }
313 |
314 | if providers.apple.is_some() {
315 | let provider = providers.apple.unwrap();
316 | let url = provider.actions[0].uri.clone();
317 | let mut button = serenity::builder::CreateButton::default();
318 | let emoji = ReactionType::try_from("<:Apple Music:1014769073277640765>").unwrap();
319 |
320 | button.label("Apple Music")
321 | .style(ButtonStyle::Link)
322 | .url(&url)
323 | .emoji(emoji);
324 | buttons.push(button);
325 | }
326 |
327 | let query = encode(&format!("{} {}", title, artist)).to_string();
328 | let url = "https://music.youtube.com/search?q=".to_string() + &query;
329 | let mut button = serenity::builder::CreateButton::default();
330 | let emoji = ReactionType::try_from("<:YouTube Music:1016942966012661762>").unwrap();
331 |
332 | button.label("YouTube Music")
333 | .style(ButtonStyle::Link)
334 | .url(&url)
335 | .emoji(emoji);
336 | buttons.push(button);
337 |
338 | // if providers.deezer.is_some() {
339 | // // Shazam's Deezer links don't work in the web client, so we need to generate our own based on track title and artist name
340 | // let query = encode(&format!("{} {}", title, artist)).to_string();
341 | // let url = format!("https://www.deezer.com/search/{}", query);
342 | // let mut button = serenity::builder::CreateButton::default();
343 | // let emoji = ReactionType::try_from("<:Deezer:1016912951355125812>").unwrap();
344 |
345 | // button.label("Deezer")
346 | // .style(ButtonStyle::Link)
347 | // .url(&url)
348 | // .emoji(emoji);
349 | // buttons.push(button);
350 | // }
351 |
352 | // Create Action Row
353 | let mut action_row = serenity::builder::CreateActionRow::default();
354 | // Put buttons into action row
355 | for button in buttons {
356 | action_row.add_button(button);
357 | }
358 |
359 | // Cycle through metadata and add each as a field
360 | for section in track.sections {
361 | if section.metadata.is_some() {
362 | let metadata = section.metadata.unwrap();
363 | for item in metadata {
364 | embed.field(item.title, item.text, true);
365 | }
366 | }
367 | }
368 |
369 | // Send as an interaction followup if this is part of an interaction
370 | if interaction.is_some() {
371 | // Send as an followup message
372 | if let Interaction::ApplicationCommand(command) = interaction.unwrap() {
373 | command.create_followup_message(&ctx.http, |f| {
374 | f.content(message)
375 | .embed(|e| {
376 | e.0 = embed.0;
377 | e
378 | }).components(|f| {
379 | f.create_action_row(|a| {
380 | a.0 = action_row.0;
381 | a
382 | })
383 | })
384 | }).await.unwrap();
385 | }
386 |
387 | } else {
388 | if let Err(why) = msg.channel_id.send_message(&ctx.http, |m|
389 | m.content(message)
390 | .add_embed(|e| {
391 | e.0 = embed.0;
392 | e
393 | }).components(|f| {
394 | f.create_action_row(|a| {
395 | a.0 = action_row.0;
396 | a
397 | })
398 | })
399 | .reference_message(msg)
400 | ).await {
401 | println!("Error sending message: {:?}", why);
402 | }
403 | }
404 |
405 | }
406 |
407 | async fn start_typing(ctx: &Context, msg: &serenity::model::channel::Message, interaction: &Option) {
408 | if interaction.is_none() {
409 | if let Err(why) = msg.channel_id.broadcast_typing(&ctx.http).await {
410 | println!("Error setting typing state: {:?}", why);
411 | }
412 | }
413 | }
414 |
415 | async fn check_message(ctx: Context, msg: &serenity::model::channel::Message, interaction: Option) {
416 | if !msg.attachments.is_empty() {
417 | let interaction = interaction.clone();
418 | let ctx = ctx.clone();
419 |
420 | println!("Attachments: {:?}", &msg.attachments);
421 | // Iterate through attachments and find the first one with a content_type that contains "video"
422 | for attachment in &msg.attachments {
423 | let content_type = attachment.content_type.as_ref().unwrap();
424 | if content_type.contains("video") || content_type.contains("audio") {
425 | println!("Found media attachment: {}", attachment.url);
426 |
427 | start_typing(&ctx, msg, &interaction).await;
428 | handle_response(ctx, &msg, fetch_direct(&attachment.url).await, interaction).await;
429 |
430 | println!("Fetched from API!");
431 | return;
432 | }
433 | }
434 | }
435 | // Scan embeds for direct download media
436 | if !msg.embeds.is_empty() {
437 | let interaction = interaction.clone();
438 | let ctx = ctx.clone();
439 |
440 | println!("Embeds: {:?}", &msg.embeds);
441 | for embed in &msg.embeds {
442 | if let Some(url) = &embed.url {
443 | if should_direct_download(url) {
444 | println!("Found media embed: {}", url);
445 |
446 | start_typing(&ctx, msg, &interaction).await;
447 | handle_response(ctx, &msg, fetch_direct(&url).await, interaction).await;
448 |
449 | println!("Fetched from API!");
450 | return;
451 | } else if matches_twitter_link(url) {
452 | println!("Found twitter link: {}", url);
453 |
454 | start_typing(&ctx, msg, &interaction).await;
455 | handle_response(ctx, &msg, fetch_twitter(&url).await, interaction).await;
456 |
457 | println!("Fetched from API!");
458 | return;
459 | }
460 | }
461 | }
462 | }
463 | // Scan for links
464 | if !msg.content.is_empty() {
465 |
466 | let interaction = interaction.clone();
467 | let ctx = ctx.clone();
468 | println!("Content: {}", &msg.content);
469 |
470 | // Match links using LINK_REGEX
471 | for link in LINK_REGEX.find_iter(&msg.content) {
472 |
473 | let url = link.as_str();
474 | println!("Found link: {}", url);
475 |
476 | // Check if the link is a direct download link
477 | if should_direct_download(url) {
478 | println!("Found media: {}", url);
479 |
480 | start_typing(&ctx, msg, &interaction).await;
481 | handle_response(ctx, &msg, fetch_direct(&url).await, interaction).await;
482 | return;
483 | } else if matches_twitter_link(url) {
484 | println!("Found twitter link: {}", url);
485 |
486 | start_typing(&ctx, msg, &interaction).await;
487 | handle_response(ctx, &msg, fetch_twitter(&url).await, interaction).await;
488 | return;
489 | } else {
490 | println!("Let's try processing link using ytdl method: {}", url);
491 |
492 | start_typing(&ctx, msg, &interaction).await;
493 | handle_response(ctx, &msg, fetch_ytdl(&url).await, interaction).await;
494 | return;
495 | }
496 |
497 | }
498 | }
499 | }
500 |
501 | #[async_trait]
502 | impl EventHandler for Handler {
503 | async fn message(&self, ctx: Context, msg: serenity::model::channel::Message) {
504 | // If message is empty and has no attachments, then return
505 | if msg.content.is_empty() && msg.attachments.is_empty() {
506 | return;
507 | }
508 |
509 | if msg.author.bot { return; } // Ignore pings from bots
510 | println!("CREATE_MESSAGE from {}", msg.author.name);
511 |
512 | check_message(ctx, &msg, None).await;
513 | }
514 |
515 | async fn ready(&self, ctx: Context, ready: Ready) {
516 | if let Some(shard) = ready.shard {
517 | // Note that array index 0 is 0-indexed, while index 1 is 1-indexed.
518 | //
519 | // This may seem unintuitive, but it models Discord's behaviour.
520 | println!("READY ({}) on shard {}/{}!", ready.user.name, shard[0], shard[1],);
521 |
522 | ctx.set_activity(Activity::listening("your music!")).await;
523 | }
524 | }
525 |
526 | async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
527 | let interaction_clone = interaction.clone();
528 | if let Interaction::ApplicationCommand(command) = interaction {
529 | // println!("Received command interaction: {:#?}", command);
530 | let name = &command.data.name;
531 |
532 | if name == "help" {
533 | if let Err(why) = command
534 | .create_interaction_response(&ctx.http, |response| {
535 | response
536 | .kind(InteractionResponseType::ChannelMessageWithSource)
537 | .interaction_response_data(|message| {
538 | message.embed(|embed| {
539 | embed.title("What's That Song?")
540 | .description("**Figure out what song is playing with videos, audio files, and web URLs on Discord.**
541 |
542 | There are a few ways you can use the bot:
543 |
544 | :one: If you have access to use application commands in a server, you will be able to match other people's media and URLs by right clicking their message and choosing **Apps > What's That Song?**. The results will be sent to you privately.
545 |
546 | :two: Send a message in a server **@ mentioning the bot** with a URL or media file.
547 |
548 | :three: **DM the bot** with a URL or media file.")
549 | .color(Colour::BLUE)
550 | }).flags(MessageFlags::EPHEMERAL)
551 | })
552 | })
553 | .await
554 | {
555 | println!("Cannot respond to application command: {}", why);
556 | }
557 | } else {
558 | // let's send a deferred ephemeral response so we can process the music
559 | if let Err(why) = command
560 | .create_interaction_response(&ctx.http, |response| {
561 | response.kind(InteractionResponseType::DeferredChannelMessageWithSource)
562 | .interaction_response_data(|message| {
563 | message.flags(MessageFlags::EPHEMERAL)
564 | })
565 | }).await
566 | {
567 | println!("Cannot respond to application command: {}", why);
568 | }
569 | // Get message data
570 | let messages = command.data.resolved.messages;
571 | let target_id = command.data.target_id.unwrap();
572 | // Get message from target_id
573 | let message_id = target_id.to_message_id();
574 | let message = messages.get(&message_id).unwrap();
575 |
576 | check_message(ctx, message, Some(interaction_clone)).await;
577 | }
578 | }
579 | }
580 | }
581 |
582 | #[tokio::main]
583 | async fn main() {
584 |
585 | dotenv::dotenv().expect("Failed to load .env file!");
586 | let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment");
587 |
588 | let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::DIRECT_MESSAGES;
589 | let mut client =
590 | Client::builder(&token, intents).event_handler(Handler).await.expect("Err creating client");
591 |
592 | let manager = client.shard_manager.clone();
593 |
594 | tokio::spawn(async move {
595 | loop {
596 | sleep(Duration::from_secs(30)).await;
597 |
598 | let lock = manager.lock().await;
599 | let shard_runners = lock.runners.lock().await;
600 |
601 | for (id, runner) in shard_runners.iter() {
602 | println!(
603 | "Shard ID {} is {} with a latency of {:?}",
604 | id, runner.stage, runner.latency,
605 | );
606 | }
607 | }
608 | });
609 |
610 | if let Err(why) = client.start_shards(1).await {
611 | println!("Client error: {:?}", why);
612 | }
613 | }
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "adler"
7 | version = "1.0.2"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
10 |
11 | [[package]]
12 | name = "aho-corasick"
13 | version = "0.7.19"
14 | source = "registry+https://github.com/rust-lang/crates.io-index"
15 | checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
16 | dependencies = [
17 | "memchr",
18 | ]
19 |
20 | [[package]]
21 | name = "android_system_properties"
22 | version = "0.1.5"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
25 | dependencies = [
26 | "libc",
27 | ]
28 |
29 | [[package]]
30 | name = "async-trait"
31 | version = "0.1.57"
32 | source = "registry+https://github.com/rust-lang/crates.io-index"
33 | checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f"
34 | dependencies = [
35 | "proc-macro2",
36 | "quote",
37 | "syn",
38 | ]
39 |
40 | [[package]]
41 | name = "async-tungstenite"
42 | version = "0.17.2"
43 | source = "registry+https://github.com/rust-lang/crates.io-index"
44 | checksum = "a1b71b31561643aa8e7df3effe284fa83ab1a840e52294c5f4bd7bfd8b2becbb"
45 | dependencies = [
46 | "futures-io",
47 | "futures-util",
48 | "log",
49 | "pin-project-lite",
50 | "tokio",
51 | "tokio-rustls",
52 | "tungstenite",
53 | "webpki-roots",
54 | ]
55 |
56 | [[package]]
57 | name = "autocfg"
58 | version = "1.1.0"
59 | source = "registry+https://github.com/rust-lang/crates.io-index"
60 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
61 |
62 | [[package]]
63 | name = "base64"
64 | version = "0.13.0"
65 | source = "registry+https://github.com/rust-lang/crates.io-index"
66 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
67 |
68 | [[package]]
69 | name = "bitflags"
70 | version = "1.3.2"
71 | source = "registry+https://github.com/rust-lang/crates.io-index"
72 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
73 |
74 | [[package]]
75 | name = "block-buffer"
76 | version = "0.10.2"
77 | source = "registry+https://github.com/rust-lang/crates.io-index"
78 | checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
79 | dependencies = [
80 | "generic-array",
81 | ]
82 |
83 | [[package]]
84 | name = "bumpalo"
85 | version = "3.11.0"
86 | source = "registry+https://github.com/rust-lang/crates.io-index"
87 | checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
88 |
89 | [[package]]
90 | name = "byteorder"
91 | version = "1.4.3"
92 | source = "registry+https://github.com/rust-lang/crates.io-index"
93 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
94 |
95 | [[package]]
96 | name = "bytes"
97 | version = "1.2.1"
98 | source = "registry+https://github.com/rust-lang/crates.io-index"
99 | checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
100 |
101 | [[package]]
102 | name = "cc"
103 | version = "1.0.73"
104 | source = "registry+https://github.com/rust-lang/crates.io-index"
105 | checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
106 |
107 | [[package]]
108 | name = "cfg-if"
109 | version = "1.0.0"
110 | source = "registry+https://github.com/rust-lang/crates.io-index"
111 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
112 |
113 | [[package]]
114 | name = "chrono"
115 | version = "0.4.22"
116 | source = "registry+https://github.com/rust-lang/crates.io-index"
117 | checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
118 | dependencies = [
119 | "iana-time-zone",
120 | "num-integer",
121 | "num-traits",
122 | "serde",
123 | "winapi",
124 | ]
125 |
126 | [[package]]
127 | name = "core-foundation"
128 | version = "0.9.3"
129 | source = "registry+https://github.com/rust-lang/crates.io-index"
130 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
131 | dependencies = [
132 | "core-foundation-sys",
133 | "libc",
134 | ]
135 |
136 | [[package]]
137 | name = "core-foundation-sys"
138 | version = "0.8.3"
139 | source = "registry+https://github.com/rust-lang/crates.io-index"
140 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
141 |
142 | [[package]]
143 | name = "cpufeatures"
144 | version = "0.2.4"
145 | source = "registry+https://github.com/rust-lang/crates.io-index"
146 | checksum = "dc948ebb96241bb40ab73effeb80d9f93afaad49359d159a5e61be51619fe813"
147 | dependencies = [
148 | "libc",
149 | ]
150 |
151 | [[package]]
152 | name = "crc32fast"
153 | version = "1.3.2"
154 | source = "registry+https://github.com/rust-lang/crates.io-index"
155 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
156 | dependencies = [
157 | "cfg-if",
158 | ]
159 |
160 | [[package]]
161 | name = "crypto-common"
162 | version = "0.1.6"
163 | source = "registry+https://github.com/rust-lang/crates.io-index"
164 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
165 | dependencies = [
166 | "generic-array",
167 | "typenum",
168 | ]
169 |
170 | [[package]]
171 | name = "dashmap"
172 | version = "5.4.0"
173 | source = "registry+https://github.com/rust-lang/crates.io-index"
174 | checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc"
175 | dependencies = [
176 | "cfg-if",
177 | "hashbrown",
178 | "lock_api",
179 | "once_cell",
180 | "parking_lot_core",
181 | "serde",
182 | ]
183 |
184 | [[package]]
185 | name = "digest"
186 | version = "0.10.3"
187 | source = "registry+https://github.com/rust-lang/crates.io-index"
188 | checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
189 | dependencies = [
190 | "block-buffer",
191 | "crypto-common",
192 | ]
193 |
194 | [[package]]
195 | name = "dotenv"
196 | version = "0.15.0"
197 | source = "registry+https://github.com/rust-lang/crates.io-index"
198 | checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
199 |
200 | [[package]]
201 | name = "encoding_rs"
202 | version = "0.8.31"
203 | source = "registry+https://github.com/rust-lang/crates.io-index"
204 | checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b"
205 | dependencies = [
206 | "cfg-if",
207 | ]
208 |
209 | [[package]]
210 | name = "fastrand"
211 | version = "1.8.0"
212 | source = "registry+https://github.com/rust-lang/crates.io-index"
213 | checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
214 | dependencies = [
215 | "instant",
216 | ]
217 |
218 | [[package]]
219 | name = "flate2"
220 | version = "1.0.24"
221 | source = "registry+https://github.com/rust-lang/crates.io-index"
222 | checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
223 | dependencies = [
224 | "crc32fast",
225 | "miniz_oxide",
226 | ]
227 |
228 | [[package]]
229 | name = "fnv"
230 | version = "1.0.7"
231 | source = "registry+https://github.com/rust-lang/crates.io-index"
232 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
233 |
234 | [[package]]
235 | name = "foreign-types"
236 | version = "0.3.2"
237 | source = "registry+https://github.com/rust-lang/crates.io-index"
238 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
239 | dependencies = [
240 | "foreign-types-shared",
241 | ]
242 |
243 | [[package]]
244 | name = "foreign-types-shared"
245 | version = "0.1.1"
246 | source = "registry+https://github.com/rust-lang/crates.io-index"
247 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
248 |
249 | [[package]]
250 | name = "form_urlencoded"
251 | version = "1.0.1"
252 | source = "registry+https://github.com/rust-lang/crates.io-index"
253 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
254 | dependencies = [
255 | "matches",
256 | "percent-encoding",
257 | ]
258 |
259 | [[package]]
260 | name = "futures"
261 | version = "0.3.24"
262 | source = "registry+https://github.com/rust-lang/crates.io-index"
263 | checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c"
264 | dependencies = [
265 | "futures-channel",
266 | "futures-core",
267 | "futures-io",
268 | "futures-sink",
269 | "futures-task",
270 | "futures-util",
271 | ]
272 |
273 | [[package]]
274 | name = "futures-channel"
275 | version = "0.3.24"
276 | source = "registry+https://github.com/rust-lang/crates.io-index"
277 | checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050"
278 | dependencies = [
279 | "futures-core",
280 | "futures-sink",
281 | ]
282 |
283 | [[package]]
284 | name = "futures-core"
285 | version = "0.3.24"
286 | source = "registry+https://github.com/rust-lang/crates.io-index"
287 | checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf"
288 |
289 | [[package]]
290 | name = "futures-io"
291 | version = "0.3.24"
292 | source = "registry+https://github.com/rust-lang/crates.io-index"
293 | checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68"
294 |
295 | [[package]]
296 | name = "futures-sink"
297 | version = "0.3.24"
298 | source = "registry+https://github.com/rust-lang/crates.io-index"
299 | checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56"
300 |
301 | [[package]]
302 | name = "futures-task"
303 | version = "0.3.24"
304 | source = "registry+https://github.com/rust-lang/crates.io-index"
305 | checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1"
306 |
307 | [[package]]
308 | name = "futures-util"
309 | version = "0.3.24"
310 | source = "registry+https://github.com/rust-lang/crates.io-index"
311 | checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90"
312 | dependencies = [
313 | "futures-channel",
314 | "futures-core",
315 | "futures-io",
316 | "futures-sink",
317 | "futures-task",
318 | "memchr",
319 | "pin-project-lite",
320 | "pin-utils",
321 | "slab",
322 | ]
323 |
324 | [[package]]
325 | name = "generic-array"
326 | version = "0.14.6"
327 | source = "registry+https://github.com/rust-lang/crates.io-index"
328 | checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
329 | dependencies = [
330 | "typenum",
331 | "version_check",
332 | ]
333 |
334 | [[package]]
335 | name = "getrandom"
336 | version = "0.2.7"
337 | source = "registry+https://github.com/rust-lang/crates.io-index"
338 | checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
339 | dependencies = [
340 | "cfg-if",
341 | "libc",
342 | "wasi",
343 | ]
344 |
345 | [[package]]
346 | name = "h2"
347 | version = "0.3.14"
348 | source = "registry+https://github.com/rust-lang/crates.io-index"
349 | checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be"
350 | dependencies = [
351 | "bytes",
352 | "fnv",
353 | "futures-core",
354 | "futures-sink",
355 | "futures-util",
356 | "http",
357 | "indexmap",
358 | "slab",
359 | "tokio",
360 | "tokio-util",
361 | "tracing",
362 | ]
363 |
364 | [[package]]
365 | name = "hashbrown"
366 | version = "0.12.3"
367 | source = "registry+https://github.com/rust-lang/crates.io-index"
368 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
369 |
370 | [[package]]
371 | name = "hermit-abi"
372 | version = "0.1.19"
373 | source = "registry+https://github.com/rust-lang/crates.io-index"
374 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
375 | dependencies = [
376 | "libc",
377 | ]
378 |
379 | [[package]]
380 | name = "http"
381 | version = "0.2.8"
382 | source = "registry+https://github.com/rust-lang/crates.io-index"
383 | checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
384 | dependencies = [
385 | "bytes",
386 | "fnv",
387 | "itoa",
388 | ]
389 |
390 | [[package]]
391 | name = "http-body"
392 | version = "0.4.5"
393 | source = "registry+https://github.com/rust-lang/crates.io-index"
394 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
395 | dependencies = [
396 | "bytes",
397 | "http",
398 | "pin-project-lite",
399 | ]
400 |
401 | [[package]]
402 | name = "httparse"
403 | version = "1.8.0"
404 | source = "registry+https://github.com/rust-lang/crates.io-index"
405 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
406 |
407 | [[package]]
408 | name = "httpdate"
409 | version = "1.0.2"
410 | source = "registry+https://github.com/rust-lang/crates.io-index"
411 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
412 |
413 | [[package]]
414 | name = "hyper"
415 | version = "0.14.20"
416 | source = "registry+https://github.com/rust-lang/crates.io-index"
417 | checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac"
418 | dependencies = [
419 | "bytes",
420 | "futures-channel",
421 | "futures-core",
422 | "futures-util",
423 | "h2",
424 | "http",
425 | "http-body",
426 | "httparse",
427 | "httpdate",
428 | "itoa",
429 | "pin-project-lite",
430 | "socket2",
431 | "tokio",
432 | "tower-service",
433 | "tracing",
434 | "want",
435 | ]
436 |
437 | [[package]]
438 | name = "hyper-rustls"
439 | version = "0.23.0"
440 | source = "registry+https://github.com/rust-lang/crates.io-index"
441 | checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac"
442 | dependencies = [
443 | "http",
444 | "hyper",
445 | "rustls",
446 | "tokio",
447 | "tokio-rustls",
448 | ]
449 |
450 | [[package]]
451 | name = "hyper-tls"
452 | version = "0.5.0"
453 | source = "registry+https://github.com/rust-lang/crates.io-index"
454 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
455 | dependencies = [
456 | "bytes",
457 | "hyper",
458 | "native-tls",
459 | "tokio",
460 | "tokio-native-tls",
461 | ]
462 |
463 | [[package]]
464 | name = "iana-time-zone"
465 | version = "0.1.47"
466 | source = "registry+https://github.com/rust-lang/crates.io-index"
467 | checksum = "4c495f162af0bf17656d0014a0eded5f3cd2f365fdd204548c2869db89359dc7"
468 | dependencies = [
469 | "android_system_properties",
470 | "core-foundation-sys",
471 | "js-sys",
472 | "once_cell",
473 | "wasm-bindgen",
474 | "winapi",
475 | ]
476 |
477 | [[package]]
478 | name = "idna"
479 | version = "0.2.3"
480 | source = "registry+https://github.com/rust-lang/crates.io-index"
481 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
482 | dependencies = [
483 | "matches",
484 | "unicode-bidi",
485 | "unicode-normalization",
486 | ]
487 |
488 | [[package]]
489 | name = "indexmap"
490 | version = "1.9.1"
491 | source = "registry+https://github.com/rust-lang/crates.io-index"
492 | checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
493 | dependencies = [
494 | "autocfg",
495 | "hashbrown",
496 | ]
497 |
498 | [[package]]
499 | name = "instant"
500 | version = "0.1.12"
501 | source = "registry+https://github.com/rust-lang/crates.io-index"
502 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
503 | dependencies = [
504 | "cfg-if",
505 | ]
506 |
507 | [[package]]
508 | name = "ipnet"
509 | version = "2.5.0"
510 | source = "registry+https://github.com/rust-lang/crates.io-index"
511 | checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
512 |
513 | [[package]]
514 | name = "itoa"
515 | version = "1.0.3"
516 | source = "registry+https://github.com/rust-lang/crates.io-index"
517 | checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
518 |
519 | [[package]]
520 | name = "js-sys"
521 | version = "0.3.59"
522 | source = "registry+https://github.com/rust-lang/crates.io-index"
523 | checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2"
524 | dependencies = [
525 | "wasm-bindgen",
526 | ]
527 |
528 | [[package]]
529 | name = "lazy_static"
530 | version = "1.4.0"
531 | source = "registry+https://github.com/rust-lang/crates.io-index"
532 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
533 |
534 | [[package]]
535 | name = "libc"
536 | version = "0.2.132"
537 | source = "registry+https://github.com/rust-lang/crates.io-index"
538 | checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
539 |
540 | [[package]]
541 | name = "lock_api"
542 | version = "0.4.8"
543 | source = "registry+https://github.com/rust-lang/crates.io-index"
544 | checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390"
545 | dependencies = [
546 | "autocfg",
547 | "scopeguard",
548 | ]
549 |
550 | [[package]]
551 | name = "log"
552 | version = "0.4.17"
553 | source = "registry+https://github.com/rust-lang/crates.io-index"
554 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
555 | dependencies = [
556 | "cfg-if",
557 | ]
558 |
559 | [[package]]
560 | name = "matches"
561 | version = "0.1.9"
562 | source = "registry+https://github.com/rust-lang/crates.io-index"
563 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
564 |
565 | [[package]]
566 | name = "memchr"
567 | version = "2.5.0"
568 | source = "registry+https://github.com/rust-lang/crates.io-index"
569 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
570 |
571 | [[package]]
572 | name = "mime"
573 | version = "0.3.16"
574 | source = "registry+https://github.com/rust-lang/crates.io-index"
575 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
576 |
577 | [[package]]
578 | name = "mime_guess"
579 | version = "2.0.4"
580 | source = "registry+https://github.com/rust-lang/crates.io-index"
581 | checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
582 | dependencies = [
583 | "mime",
584 | "unicase",
585 | ]
586 |
587 | [[package]]
588 | name = "miniz_oxide"
589 | version = "0.5.3"
590 | source = "registry+https://github.com/rust-lang/crates.io-index"
591 | checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
592 | dependencies = [
593 | "adler",
594 | ]
595 |
596 | [[package]]
597 | name = "mio"
598 | version = "0.8.4"
599 | source = "registry+https://github.com/rust-lang/crates.io-index"
600 | checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
601 | dependencies = [
602 | "libc",
603 | "log",
604 | "wasi",
605 | "windows-sys",
606 | ]
607 |
608 | [[package]]
609 | name = "native-tls"
610 | version = "0.2.10"
611 | source = "registry+https://github.com/rust-lang/crates.io-index"
612 | checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9"
613 | dependencies = [
614 | "lazy_static",
615 | "libc",
616 | "log",
617 | "openssl",
618 | "openssl-probe",
619 | "openssl-sys",
620 | "schannel",
621 | "security-framework",
622 | "security-framework-sys",
623 | "tempfile",
624 | ]
625 |
626 | [[package]]
627 | name = "num-integer"
628 | version = "0.1.45"
629 | source = "registry+https://github.com/rust-lang/crates.io-index"
630 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
631 | dependencies = [
632 | "autocfg",
633 | "num-traits",
634 | ]
635 |
636 | [[package]]
637 | name = "num-traits"
638 | version = "0.2.15"
639 | source = "registry+https://github.com/rust-lang/crates.io-index"
640 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
641 | dependencies = [
642 | "autocfg",
643 | ]
644 |
645 | [[package]]
646 | name = "num_cpus"
647 | version = "1.13.1"
648 | source = "registry+https://github.com/rust-lang/crates.io-index"
649 | checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
650 | dependencies = [
651 | "hermit-abi",
652 | "libc",
653 | ]
654 |
655 | [[package]]
656 | name = "num_threads"
657 | version = "0.1.6"
658 | source = "registry+https://github.com/rust-lang/crates.io-index"
659 | checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
660 | dependencies = [
661 | "libc",
662 | ]
663 |
664 | [[package]]
665 | name = "once_cell"
666 | version = "1.14.0"
667 | source = "registry+https://github.com/rust-lang/crates.io-index"
668 | checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
669 |
670 | [[package]]
671 | name = "openssl"
672 | version = "0.10.41"
673 | source = "registry+https://github.com/rust-lang/crates.io-index"
674 | checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0"
675 | dependencies = [
676 | "bitflags",
677 | "cfg-if",
678 | "foreign-types",
679 | "libc",
680 | "once_cell",
681 | "openssl-macros",
682 | "openssl-sys",
683 | ]
684 |
685 | [[package]]
686 | name = "openssl-macros"
687 | version = "0.1.0"
688 | source = "registry+https://github.com/rust-lang/crates.io-index"
689 | checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
690 | dependencies = [
691 | "proc-macro2",
692 | "quote",
693 | "syn",
694 | ]
695 |
696 | [[package]]
697 | name = "openssl-probe"
698 | version = "0.1.5"
699 | source = "registry+https://github.com/rust-lang/crates.io-index"
700 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
701 |
702 | [[package]]
703 | name = "openssl-sys"
704 | version = "0.9.75"
705 | source = "registry+https://github.com/rust-lang/crates.io-index"
706 | checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f"
707 | dependencies = [
708 | "autocfg",
709 | "cc",
710 | "libc",
711 | "pkg-config",
712 | "vcpkg",
713 | ]
714 |
715 | [[package]]
716 | name = "ordered-float"
717 | version = "2.10.0"
718 | source = "registry+https://github.com/rust-lang/crates.io-index"
719 | checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87"
720 | dependencies = [
721 | "num-traits",
722 | ]
723 |
724 | [[package]]
725 | name = "parking_lot"
726 | version = "0.12.1"
727 | source = "registry+https://github.com/rust-lang/crates.io-index"
728 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
729 | dependencies = [
730 | "lock_api",
731 | "parking_lot_core",
732 | ]
733 |
734 | [[package]]
735 | name = "parking_lot_core"
736 | version = "0.9.3"
737 | source = "registry+https://github.com/rust-lang/crates.io-index"
738 | checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
739 | dependencies = [
740 | "cfg-if",
741 | "libc",
742 | "redox_syscall",
743 | "smallvec",
744 | "windows-sys",
745 | ]
746 |
747 | [[package]]
748 | name = "percent-encoding"
749 | version = "2.1.0"
750 | source = "registry+https://github.com/rust-lang/crates.io-index"
751 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
752 |
753 | [[package]]
754 | name = "pin-project-lite"
755 | version = "0.2.9"
756 | source = "registry+https://github.com/rust-lang/crates.io-index"
757 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
758 |
759 | [[package]]
760 | name = "pin-utils"
761 | version = "0.1.0"
762 | source = "registry+https://github.com/rust-lang/crates.io-index"
763 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
764 |
765 | [[package]]
766 | name = "pkg-config"
767 | version = "0.3.25"
768 | source = "registry+https://github.com/rust-lang/crates.io-index"
769 | checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
770 |
771 | [[package]]
772 | name = "ppv-lite86"
773 | version = "0.2.16"
774 | source = "registry+https://github.com/rust-lang/crates.io-index"
775 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
776 |
777 | [[package]]
778 | name = "proc-macro2"
779 | version = "1.0.43"
780 | source = "registry+https://github.com/rust-lang/crates.io-index"
781 | checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
782 | dependencies = [
783 | "unicode-ident",
784 | ]
785 |
786 | [[package]]
787 | name = "quote"
788 | version = "1.0.21"
789 | source = "registry+https://github.com/rust-lang/crates.io-index"
790 | checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
791 | dependencies = [
792 | "proc-macro2",
793 | ]
794 |
795 | [[package]]
796 | name = "rand"
797 | version = "0.8.5"
798 | source = "registry+https://github.com/rust-lang/crates.io-index"
799 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
800 | dependencies = [
801 | "libc",
802 | "rand_chacha",
803 | "rand_core",
804 | ]
805 |
806 | [[package]]
807 | name = "rand_chacha"
808 | version = "0.3.1"
809 | source = "registry+https://github.com/rust-lang/crates.io-index"
810 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
811 | dependencies = [
812 | "ppv-lite86",
813 | "rand_core",
814 | ]
815 |
816 | [[package]]
817 | name = "rand_core"
818 | version = "0.6.3"
819 | source = "registry+https://github.com/rust-lang/crates.io-index"
820 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
821 | dependencies = [
822 | "getrandom",
823 | ]
824 |
825 | [[package]]
826 | name = "redox_syscall"
827 | version = "0.2.16"
828 | source = "registry+https://github.com/rust-lang/crates.io-index"
829 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
830 | dependencies = [
831 | "bitflags",
832 | ]
833 |
834 | [[package]]
835 | name = "regex"
836 | version = "1.6.0"
837 | source = "registry+https://github.com/rust-lang/crates.io-index"
838 | checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
839 | dependencies = [
840 | "aho-corasick",
841 | "memchr",
842 | "regex-syntax",
843 | ]
844 |
845 | [[package]]
846 | name = "regex-syntax"
847 | version = "0.6.27"
848 | source = "registry+https://github.com/rust-lang/crates.io-index"
849 | checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
850 |
851 | [[package]]
852 | name = "remove_dir_all"
853 | version = "0.5.3"
854 | source = "registry+https://github.com/rust-lang/crates.io-index"
855 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
856 | dependencies = [
857 | "winapi",
858 | ]
859 |
860 | [[package]]
861 | name = "reqwest"
862 | version = "0.11.11"
863 | source = "registry+https://github.com/rust-lang/crates.io-index"
864 | checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92"
865 | dependencies = [
866 | "base64",
867 | "bytes",
868 | "encoding_rs",
869 | "futures-core",
870 | "futures-util",
871 | "h2",
872 | "http",
873 | "http-body",
874 | "hyper",
875 | "hyper-rustls",
876 | "hyper-tls",
877 | "ipnet",
878 | "js-sys",
879 | "lazy_static",
880 | "log",
881 | "mime",
882 | "mime_guess",
883 | "native-tls",
884 | "percent-encoding",
885 | "pin-project-lite",
886 | "rustls",
887 | "rustls-pemfile",
888 | "serde",
889 | "serde_json",
890 | "serde_urlencoded",
891 | "tokio",
892 | "tokio-native-tls",
893 | "tokio-rustls",
894 | "tokio-util",
895 | "tower-service",
896 | "url",
897 | "wasm-bindgen",
898 | "wasm-bindgen-futures",
899 | "web-sys",
900 | "webpki-roots",
901 | "winreg",
902 | ]
903 |
904 | [[package]]
905 | name = "ring"
906 | version = "0.16.20"
907 | source = "registry+https://github.com/rust-lang/crates.io-index"
908 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
909 | dependencies = [
910 | "cc",
911 | "libc",
912 | "once_cell",
913 | "spin",
914 | "untrusted",
915 | "web-sys",
916 | "winapi",
917 | ]
918 |
919 | [[package]]
920 | name = "rustls"
921 | version = "0.20.6"
922 | source = "registry+https://github.com/rust-lang/crates.io-index"
923 | checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033"
924 | dependencies = [
925 | "log",
926 | "ring",
927 | "sct",
928 | "webpki",
929 | ]
930 |
931 | [[package]]
932 | name = "rustls-pemfile"
933 | version = "1.0.1"
934 | source = "registry+https://github.com/rust-lang/crates.io-index"
935 | checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55"
936 | dependencies = [
937 | "base64",
938 | ]
939 |
940 | [[package]]
941 | name = "ryu"
942 | version = "1.0.11"
943 | source = "registry+https://github.com/rust-lang/crates.io-index"
944 | checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
945 |
946 | [[package]]
947 | name = "schannel"
948 | version = "0.1.20"
949 | source = "registry+https://github.com/rust-lang/crates.io-index"
950 | checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
951 | dependencies = [
952 | "lazy_static",
953 | "windows-sys",
954 | ]
955 |
956 | [[package]]
957 | name = "scopeguard"
958 | version = "1.1.0"
959 | source = "registry+https://github.com/rust-lang/crates.io-index"
960 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
961 |
962 | [[package]]
963 | name = "sct"
964 | version = "0.7.0"
965 | source = "registry+https://github.com/rust-lang/crates.io-index"
966 | checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
967 | dependencies = [
968 | "ring",
969 | "untrusted",
970 | ]
971 |
972 | [[package]]
973 | name = "security-framework"
974 | version = "2.7.0"
975 | source = "registry+https://github.com/rust-lang/crates.io-index"
976 | checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c"
977 | dependencies = [
978 | "bitflags",
979 | "core-foundation",
980 | "core-foundation-sys",
981 | "libc",
982 | "security-framework-sys",
983 | ]
984 |
985 | [[package]]
986 | name = "security-framework-sys"
987 | version = "2.6.1"
988 | source = "registry+https://github.com/rust-lang/crates.io-index"
989 | checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
990 | dependencies = [
991 | "core-foundation-sys",
992 | "libc",
993 | ]
994 |
995 | [[package]]
996 | name = "serde"
997 | version = "1.0.144"
998 | source = "registry+https://github.com/rust-lang/crates.io-index"
999 | checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
1000 | dependencies = [
1001 | "serde_derive",
1002 | ]
1003 |
1004 | [[package]]
1005 | name = "serde-value"
1006 | version = "0.7.0"
1007 | source = "registry+https://github.com/rust-lang/crates.io-index"
1008 | checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
1009 | dependencies = [
1010 | "ordered-float",
1011 | "serde",
1012 | ]
1013 |
1014 | [[package]]
1015 | name = "serde_derive"
1016 | version = "1.0.144"
1017 | source = "registry+https://github.com/rust-lang/crates.io-index"
1018 | checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
1019 | dependencies = [
1020 | "proc-macro2",
1021 | "quote",
1022 | "syn",
1023 | ]
1024 |
1025 | [[package]]
1026 | name = "serde_json"
1027 | version = "1.0.85"
1028 | source = "registry+https://github.com/rust-lang/crates.io-index"
1029 | checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
1030 | dependencies = [
1031 | "itoa",
1032 | "ryu",
1033 | "serde",
1034 | ]
1035 |
1036 | [[package]]
1037 | name = "serde_urlencoded"
1038 | version = "0.7.1"
1039 | source = "registry+https://github.com/rust-lang/crates.io-index"
1040 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
1041 | dependencies = [
1042 | "form_urlencoded",
1043 | "itoa",
1044 | "ryu",
1045 | "serde",
1046 | ]
1047 |
1048 | [[package]]
1049 | name = "serenity"
1050 | version = "0.11.5"
1051 | source = "registry+https://github.com/rust-lang/crates.io-index"
1052 | checksum = "82fd5e7b5858ad96e99d440138f34f5b98e1b959ebcd3a1036203b30e78eb788"
1053 | dependencies = [
1054 | "async-trait",
1055 | "async-tungstenite",
1056 | "base64",
1057 | "bitflags",
1058 | "bytes",
1059 | "cfg-if",
1060 | "chrono",
1061 | "dashmap",
1062 | "flate2",
1063 | "futures",
1064 | "mime",
1065 | "mime_guess",
1066 | "parking_lot",
1067 | "percent-encoding",
1068 | "reqwest",
1069 | "serde",
1070 | "serde-value",
1071 | "serde_json",
1072 | "time",
1073 | "tokio",
1074 | "tracing",
1075 | "typemap_rev",
1076 | "url",
1077 | ]
1078 |
1079 | [[package]]
1080 | name = "sha-1"
1081 | version = "0.10.0"
1082 | source = "registry+https://github.com/rust-lang/crates.io-index"
1083 | checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
1084 | dependencies = [
1085 | "cfg-if",
1086 | "cpufeatures",
1087 | "digest",
1088 | ]
1089 |
1090 | [[package]]
1091 | name = "signal-hook-registry"
1092 | version = "1.4.0"
1093 | source = "registry+https://github.com/rust-lang/crates.io-index"
1094 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
1095 | dependencies = [
1096 | "libc",
1097 | ]
1098 |
1099 | [[package]]
1100 | name = "slab"
1101 | version = "0.4.7"
1102 | source = "registry+https://github.com/rust-lang/crates.io-index"
1103 | checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
1104 | dependencies = [
1105 | "autocfg",
1106 | ]
1107 |
1108 | [[package]]
1109 | name = "smallvec"
1110 | version = "1.9.0"
1111 | source = "registry+https://github.com/rust-lang/crates.io-index"
1112 | checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
1113 |
1114 | [[package]]
1115 | name = "socket2"
1116 | version = "0.4.7"
1117 | source = "registry+https://github.com/rust-lang/crates.io-index"
1118 | checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
1119 | dependencies = [
1120 | "libc",
1121 | "winapi",
1122 | ]
1123 |
1124 | [[package]]
1125 | name = "spin"
1126 | version = "0.5.2"
1127 | source = "registry+https://github.com/rust-lang/crates.io-index"
1128 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
1129 |
1130 | [[package]]
1131 | name = "syn"
1132 | version = "1.0.99"
1133 | source = "registry+https://github.com/rust-lang/crates.io-index"
1134 | checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
1135 | dependencies = [
1136 | "proc-macro2",
1137 | "quote",
1138 | "unicode-ident",
1139 | ]
1140 |
1141 | [[package]]
1142 | name = "tempfile"
1143 | version = "3.3.0"
1144 | source = "registry+https://github.com/rust-lang/crates.io-index"
1145 | checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
1146 | dependencies = [
1147 | "cfg-if",
1148 | "fastrand",
1149 | "libc",
1150 | "redox_syscall",
1151 | "remove_dir_all",
1152 | "winapi",
1153 | ]
1154 |
1155 | [[package]]
1156 | name = "thiserror"
1157 | version = "1.0.33"
1158 | source = "registry+https://github.com/rust-lang/crates.io-index"
1159 | checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57"
1160 | dependencies = [
1161 | "thiserror-impl",
1162 | ]
1163 |
1164 | [[package]]
1165 | name = "thiserror-impl"
1166 | version = "1.0.33"
1167 | source = "registry+https://github.com/rust-lang/crates.io-index"
1168 | checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09"
1169 | dependencies = [
1170 | "proc-macro2",
1171 | "quote",
1172 | "syn",
1173 | ]
1174 |
1175 | [[package]]
1176 | name = "time"
1177 | version = "0.3.14"
1178 | source = "registry+https://github.com/rust-lang/crates.io-index"
1179 | checksum = "3c3f9a28b618c3a6b9251b6908e9c99e04b9e5c02e6581ccbb67d59c34ef7f9b"
1180 | dependencies = [
1181 | "itoa",
1182 | "libc",
1183 | "num_threads",
1184 | "serde",
1185 | ]
1186 |
1187 | [[package]]
1188 | name = "tinyvec"
1189 | version = "1.6.0"
1190 | source = "registry+https://github.com/rust-lang/crates.io-index"
1191 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
1192 | dependencies = [
1193 | "tinyvec_macros",
1194 | ]
1195 |
1196 | [[package]]
1197 | name = "tinyvec_macros"
1198 | version = "0.1.0"
1199 | source = "registry+https://github.com/rust-lang/crates.io-index"
1200 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
1201 |
1202 | [[package]]
1203 | name = "tokio"
1204 | version = "1.21.0"
1205 | source = "registry+https://github.com/rust-lang/crates.io-index"
1206 | checksum = "89797afd69d206ccd11fb0ea560a44bbb87731d020670e79416d442919257d42"
1207 | dependencies = [
1208 | "autocfg",
1209 | "bytes",
1210 | "libc",
1211 | "memchr",
1212 | "mio",
1213 | "num_cpus",
1214 | "once_cell",
1215 | "parking_lot",
1216 | "pin-project-lite",
1217 | "signal-hook-registry",
1218 | "socket2",
1219 | "tokio-macros",
1220 | "winapi",
1221 | ]
1222 |
1223 | [[package]]
1224 | name = "tokio-macros"
1225 | version = "1.8.0"
1226 | source = "registry+https://github.com/rust-lang/crates.io-index"
1227 | checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
1228 | dependencies = [
1229 | "proc-macro2",
1230 | "quote",
1231 | "syn",
1232 | ]
1233 |
1234 | [[package]]
1235 | name = "tokio-native-tls"
1236 | version = "0.3.0"
1237 | source = "registry+https://github.com/rust-lang/crates.io-index"
1238 | checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
1239 | dependencies = [
1240 | "native-tls",
1241 | "tokio",
1242 | ]
1243 |
1244 | [[package]]
1245 | name = "tokio-rustls"
1246 | version = "0.23.4"
1247 | source = "registry+https://github.com/rust-lang/crates.io-index"
1248 | checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
1249 | dependencies = [
1250 | "rustls",
1251 | "tokio",
1252 | "webpki",
1253 | ]
1254 |
1255 | [[package]]
1256 | name = "tokio-util"
1257 | version = "0.7.3"
1258 | source = "registry+https://github.com/rust-lang/crates.io-index"
1259 | checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45"
1260 | dependencies = [
1261 | "bytes",
1262 | "futures-core",
1263 | "futures-sink",
1264 | "pin-project-lite",
1265 | "tokio",
1266 | "tracing",
1267 | ]
1268 |
1269 | [[package]]
1270 | name = "tower-service"
1271 | version = "0.3.2"
1272 | source = "registry+https://github.com/rust-lang/crates.io-index"
1273 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
1274 |
1275 | [[package]]
1276 | name = "tracing"
1277 | version = "0.1.36"
1278 | source = "registry+https://github.com/rust-lang/crates.io-index"
1279 | checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
1280 | dependencies = [
1281 | "cfg-if",
1282 | "log",
1283 | "pin-project-lite",
1284 | "tracing-attributes",
1285 | "tracing-core",
1286 | ]
1287 |
1288 | [[package]]
1289 | name = "tracing-attributes"
1290 | version = "0.1.22"
1291 | source = "registry+https://github.com/rust-lang/crates.io-index"
1292 | checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
1293 | dependencies = [
1294 | "proc-macro2",
1295 | "quote",
1296 | "syn",
1297 | ]
1298 |
1299 | [[package]]
1300 | name = "tracing-core"
1301 | version = "0.1.29"
1302 | source = "registry+https://github.com/rust-lang/crates.io-index"
1303 | checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
1304 | dependencies = [
1305 | "once_cell",
1306 | ]
1307 |
1308 | [[package]]
1309 | name = "try-lock"
1310 | version = "0.2.3"
1311 | source = "registry+https://github.com/rust-lang/crates.io-index"
1312 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
1313 |
1314 | [[package]]
1315 | name = "tungstenite"
1316 | version = "0.17.3"
1317 | source = "registry+https://github.com/rust-lang/crates.io-index"
1318 | checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0"
1319 | dependencies = [
1320 | "base64",
1321 | "byteorder",
1322 | "bytes",
1323 | "http",
1324 | "httparse",
1325 | "log",
1326 | "rand",
1327 | "rustls",
1328 | "sha-1",
1329 | "thiserror",
1330 | "url",
1331 | "utf-8",
1332 | "webpki",
1333 | ]
1334 |
1335 | [[package]]
1336 | name = "typemap_rev"
1337 | version = "0.1.5"
1338 | source = "registry+https://github.com/rust-lang/crates.io-index"
1339 | checksum = "ed5b74f0a24b5454580a79abb6994393b09adf0ab8070f15827cb666255de155"
1340 |
1341 | [[package]]
1342 | name = "typenum"
1343 | version = "1.15.0"
1344 | source = "registry+https://github.com/rust-lang/crates.io-index"
1345 | checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
1346 |
1347 | [[package]]
1348 | name = "unicase"
1349 | version = "2.6.0"
1350 | source = "registry+https://github.com/rust-lang/crates.io-index"
1351 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
1352 | dependencies = [
1353 | "version_check",
1354 | ]
1355 |
1356 | [[package]]
1357 | name = "unicode-bidi"
1358 | version = "0.3.8"
1359 | source = "registry+https://github.com/rust-lang/crates.io-index"
1360 | checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
1361 |
1362 | [[package]]
1363 | name = "unicode-ident"
1364 | version = "1.0.3"
1365 | source = "registry+https://github.com/rust-lang/crates.io-index"
1366 | checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
1367 |
1368 | [[package]]
1369 | name = "unicode-normalization"
1370 | version = "0.1.21"
1371 | source = "registry+https://github.com/rust-lang/crates.io-index"
1372 | checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
1373 | dependencies = [
1374 | "tinyvec",
1375 | ]
1376 |
1377 | [[package]]
1378 | name = "untrusted"
1379 | version = "0.7.1"
1380 | source = "registry+https://github.com/rust-lang/crates.io-index"
1381 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
1382 |
1383 | [[package]]
1384 | name = "url"
1385 | version = "2.2.2"
1386 | source = "registry+https://github.com/rust-lang/crates.io-index"
1387 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
1388 | dependencies = [
1389 | "form_urlencoded",
1390 | "idna",
1391 | "matches",
1392 | "percent-encoding",
1393 | "serde",
1394 | ]
1395 |
1396 | [[package]]
1397 | name = "urlencoding"
1398 | version = "2.1.2"
1399 | source = "registry+https://github.com/rust-lang/crates.io-index"
1400 | checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9"
1401 |
1402 | [[package]]
1403 | name = "utf-8"
1404 | version = "0.7.6"
1405 | source = "registry+https://github.com/rust-lang/crates.io-index"
1406 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
1407 |
1408 | [[package]]
1409 | name = "vcpkg"
1410 | version = "0.2.15"
1411 | source = "registry+https://github.com/rust-lang/crates.io-index"
1412 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
1413 |
1414 | [[package]]
1415 | name = "version_check"
1416 | version = "0.9.4"
1417 | source = "registry+https://github.com/rust-lang/crates.io-index"
1418 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
1419 |
1420 | [[package]]
1421 | name = "want"
1422 | version = "0.3.0"
1423 | source = "registry+https://github.com/rust-lang/crates.io-index"
1424 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
1425 | dependencies = [
1426 | "log",
1427 | "try-lock",
1428 | ]
1429 |
1430 | [[package]]
1431 | name = "wasi"
1432 | version = "0.11.0+wasi-snapshot-preview1"
1433 | source = "registry+https://github.com/rust-lang/crates.io-index"
1434 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1435 |
1436 | [[package]]
1437 | name = "wasm-bindgen"
1438 | version = "0.2.82"
1439 | source = "registry+https://github.com/rust-lang/crates.io-index"
1440 | checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d"
1441 | dependencies = [
1442 | "cfg-if",
1443 | "wasm-bindgen-macro",
1444 | ]
1445 |
1446 | [[package]]
1447 | name = "wasm-bindgen-backend"
1448 | version = "0.2.82"
1449 | source = "registry+https://github.com/rust-lang/crates.io-index"
1450 | checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f"
1451 | dependencies = [
1452 | "bumpalo",
1453 | "log",
1454 | "once_cell",
1455 | "proc-macro2",
1456 | "quote",
1457 | "syn",
1458 | "wasm-bindgen-shared",
1459 | ]
1460 |
1461 | [[package]]
1462 | name = "wasm-bindgen-futures"
1463 | version = "0.4.32"
1464 | source = "registry+https://github.com/rust-lang/crates.io-index"
1465 | checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad"
1466 | dependencies = [
1467 | "cfg-if",
1468 | "js-sys",
1469 | "wasm-bindgen",
1470 | "web-sys",
1471 | ]
1472 |
1473 | [[package]]
1474 | name = "wasm-bindgen-macro"
1475 | version = "0.2.82"
1476 | source = "registry+https://github.com/rust-lang/crates.io-index"
1477 | checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602"
1478 | dependencies = [
1479 | "quote",
1480 | "wasm-bindgen-macro-support",
1481 | ]
1482 |
1483 | [[package]]
1484 | name = "wasm-bindgen-macro-support"
1485 | version = "0.2.82"
1486 | source = "registry+https://github.com/rust-lang/crates.io-index"
1487 | checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da"
1488 | dependencies = [
1489 | "proc-macro2",
1490 | "quote",
1491 | "syn",
1492 | "wasm-bindgen-backend",
1493 | "wasm-bindgen-shared",
1494 | ]
1495 |
1496 | [[package]]
1497 | name = "wasm-bindgen-shared"
1498 | version = "0.2.82"
1499 | source = "registry+https://github.com/rust-lang/crates.io-index"
1500 | checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a"
1501 |
1502 | [[package]]
1503 | name = "web-sys"
1504 | version = "0.3.59"
1505 | source = "registry+https://github.com/rust-lang/crates.io-index"
1506 | checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1"
1507 | dependencies = [
1508 | "js-sys",
1509 | "wasm-bindgen",
1510 | ]
1511 |
1512 | [[package]]
1513 | name = "webpki"
1514 | version = "0.22.0"
1515 | source = "registry+https://github.com/rust-lang/crates.io-index"
1516 | checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
1517 | dependencies = [
1518 | "ring",
1519 | "untrusted",
1520 | ]
1521 |
1522 | [[package]]
1523 | name = "webpki-roots"
1524 | version = "0.22.4"
1525 | source = "registry+https://github.com/rust-lang/crates.io-index"
1526 | checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf"
1527 | dependencies = [
1528 | "webpki",
1529 | ]
1530 |
1531 | [[package]]
1532 | name = "whats-that-song"
1533 | version = "2.0.0"
1534 | dependencies = [
1535 | "dotenv",
1536 | "lazy_static",
1537 | "mime_guess",
1538 | "rand",
1539 | "regex",
1540 | "reqwest",
1541 | "serde",
1542 | "serenity",
1543 | "tokio",
1544 | "urlencoding",
1545 | ]
1546 |
1547 | [[package]]
1548 | name = "winapi"
1549 | version = "0.3.9"
1550 | source = "registry+https://github.com/rust-lang/crates.io-index"
1551 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1552 | dependencies = [
1553 | "winapi-i686-pc-windows-gnu",
1554 | "winapi-x86_64-pc-windows-gnu",
1555 | ]
1556 |
1557 | [[package]]
1558 | name = "winapi-i686-pc-windows-gnu"
1559 | version = "0.4.0"
1560 | source = "registry+https://github.com/rust-lang/crates.io-index"
1561 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1562 |
1563 | [[package]]
1564 | name = "winapi-x86_64-pc-windows-gnu"
1565 | version = "0.4.0"
1566 | source = "registry+https://github.com/rust-lang/crates.io-index"
1567 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1568 |
1569 | [[package]]
1570 | name = "windows-sys"
1571 | version = "0.36.1"
1572 | source = "registry+https://github.com/rust-lang/crates.io-index"
1573 | checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
1574 | dependencies = [
1575 | "windows_aarch64_msvc",
1576 | "windows_i686_gnu",
1577 | "windows_i686_msvc",
1578 | "windows_x86_64_gnu",
1579 | "windows_x86_64_msvc",
1580 | ]
1581 |
1582 | [[package]]
1583 | name = "windows_aarch64_msvc"
1584 | version = "0.36.1"
1585 | source = "registry+https://github.com/rust-lang/crates.io-index"
1586 | checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
1587 |
1588 | [[package]]
1589 | name = "windows_i686_gnu"
1590 | version = "0.36.1"
1591 | source = "registry+https://github.com/rust-lang/crates.io-index"
1592 | checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
1593 |
1594 | [[package]]
1595 | name = "windows_i686_msvc"
1596 | version = "0.36.1"
1597 | source = "registry+https://github.com/rust-lang/crates.io-index"
1598 | checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
1599 |
1600 | [[package]]
1601 | name = "windows_x86_64_gnu"
1602 | version = "0.36.1"
1603 | source = "registry+https://github.com/rust-lang/crates.io-index"
1604 | checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
1605 |
1606 | [[package]]
1607 | name = "windows_x86_64_msvc"
1608 | version = "0.36.1"
1609 | source = "registry+https://github.com/rust-lang/crates.io-index"
1610 | checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
1611 |
1612 | [[package]]
1613 | name = "winreg"
1614 | version = "0.10.1"
1615 | source = "registry+https://github.com/rust-lang/crates.io-index"
1616 | checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
1617 | dependencies = [
1618 | "winapi",
1619 | ]
1620 |
--------------------------------------------------------------------------------