├── .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 | 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 | --------------------------------------------------------------------------------