Skip to content
This repository was archived by the owner on Jan 23, 2019. It is now read-only.

Commit d5fc1a7

Browse files
committed
Add project files.
1 parent 2ffc071 commit d5fc1a7

File tree

15 files changed

+834
-0
lines changed

15 files changed

+834
-0
lines changed

EmoteScavenger.sln

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.27004.2009
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmoteScavenger", "EmoteScavenger\EmoteScavenger.csproj", "{24C1258C-67EE-4C73-9569-CA32284CE802}"
7+
EndProject
8+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3AEB8034-899D-4964-A4FF-9D9934FD55BD}"
9+
ProjectSection(SolutionItems) = preProject
10+
LICENSE.TXT = LICENSE.TXT
11+
NOTICE.TXT = NOTICE.TXT
12+
README.MD = README.MD
13+
EndProjectSection
14+
EndProject
15+
Global
16+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
17+
Debug|Any CPU = Debug|Any CPU
18+
Release|Any CPU = Release|Any CPU
19+
EndGlobalSection
20+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
21+
{24C1258C-67EE-4C73-9569-CA32284CE802}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22+
{24C1258C-67EE-4C73-9569-CA32284CE802}.Debug|Any CPU.Build.0 = Debug|Any CPU
23+
{24C1258C-67EE-4C73-9569-CA32284CE802}.Release|Any CPU.ActiveCfg = Release|Any CPU
24+
{24C1258C-67EE-4C73-9569-CA32284CE802}.Release|Any CPU.Build.0 = Release|Any CPU
25+
EndGlobalSection
26+
GlobalSection(SolutionProperties) = preSolution
27+
HideSolutionNode = FALSE
28+
EndGlobalSection
29+
GlobalSection(ExtensibilityGlobals) = postSolution
30+
SolutionGuid = {EB1B4AA6-5009-41A3-905A-BD692E27E0A7}
31+
EndGlobalSection
32+
EndGlobal

EmoteScavenger/AsyncExecutor.cs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace EmoteScavenger
6+
{
7+
public class AsyncExecutor
8+
{
9+
private SemaphoreSlim Semaphore { get; }
10+
11+
public AsyncExecutor()
12+
{
13+
this.Semaphore = new SemaphoreSlim(1, 1);
14+
}
15+
16+
public void Execute<TArg>(Func<TArg, Task> func, TArg arg)
17+
{
18+
this.Semaphore.Wait();
19+
20+
Exception taskex = null;
21+
22+
var are = new AutoResetEvent(false);
23+
_ = Task.Run(Executor);
24+
are.WaitOne();
25+
26+
this.Semaphore.Release();
27+
28+
if (taskex != null)
29+
throw taskex;
30+
31+
async Task Executor()
32+
{
33+
try
34+
{
35+
await func(arg);
36+
}
37+
catch (Exception ex)
38+
{
39+
taskex = ex;
40+
}
41+
42+
are.Set();
43+
}
44+
}
45+
46+
public TResult Execute<TArg, TResult>(Func<TArg, Task<TResult>> func, TArg arg)
47+
{
48+
this.Semaphore.Wait();
49+
50+
Exception taskex = null;
51+
TResult result = default;
52+
53+
var are = new AutoResetEvent(false);
54+
_ = Task.Run(Executor);
55+
are.WaitOne();
56+
57+
this.Semaphore.Release();
58+
59+
if (taskex != null)
60+
throw taskex;
61+
62+
return result;
63+
64+
async Task Executor()
65+
{
66+
try
67+
{
68+
result = await func(arg);
69+
}
70+
catch (Exception ex)
71+
{
72+
taskex = ex;
73+
}
74+
75+
are.Set();
76+
}
77+
}
78+
}
79+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System.IO;
2+
using Microsoft.EntityFrameworkCore;
3+
4+
namespace EmoteScavenger.Database
5+
{
6+
public class StorageContext : DbContext
7+
{
8+
public DbSet<StorageItem> Items { get; set; }
9+
private FileInfo DatabaseFile { get; }
10+
11+
public StorageContext(FileInfo dbf)
12+
{
13+
this.DatabaseFile = dbf;
14+
}
15+
16+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
17+
{
18+
optionsBuilder.UseSqlite($@"Filename=""{this.DatabaseFile.FullName}""");
19+
}
20+
}
21+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System.ComponentModel.DataAnnotations;
2+
using System.ComponentModel.DataAnnotations.Schema;
3+
4+
namespace EmoteScavenger.Database
5+
{
6+
[Table("ItemTable")]
7+
public class StorageItem
8+
{
9+
[Column("key"), Required, Key]
10+
public string Key { get; set; }
11+
12+
[Column("value"), Required]
13+
public string Value { get; set; }
14+
}
15+
}

EmoteScavenger/Emoji.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
3+
namespace EmoteScavenger
4+
{
5+
public struct Emoji
6+
{
7+
public string Name { get; }
8+
public ulong Id { get; }
9+
public string GuildName { get; }
10+
public ulong GuildId { get; }
11+
12+
public Emoji(string name, ulong id, string guildName, ulong guildId)
13+
{
14+
this.Name = name;
15+
this.Id = id;
16+
this.GuildName = guildName;
17+
this.GuildId = guildId;
18+
}
19+
20+
public Uri GetUri()
21+
=> new Uri($"https://cdn.discordapp.com/emojis/{this.Id}.png");
22+
}
23+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp2.0</TargetFramework>
6+
<LangVersion>7.1</LangVersion>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="DSharpPlus" Version="4.0.0-beta-00397" />
11+
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.1" />
12+
</ItemGroup>
13+
14+
</Project>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
namespace EmoteScavenger
2+
{
3+
public delegate void MessageLoggedEventHandler(string msg);
4+
}

EmoteScavenger/MultiDownloader.cs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Net.Http;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
namespace EmoteScavenger
10+
{
11+
public class MultiDownloader
12+
{
13+
private const string SOURCE_URL = "https://cdn.discordapp.com/emojis/{0}.png";
14+
15+
private HttpClient Http { get; }
16+
private SemaphoreSlim DownloadSemaphore { get; }
17+
private DirectoryInfo TargetDirectory { get; }
18+
19+
public MultiDownloader(DirectoryInfo target, int concurrencyLevel)
20+
{
21+
this.Http = new HttpClient()
22+
{
23+
BaseAddress = new Uri("https://cdn.discordapp.com/emojis/")
24+
};
25+
26+
this.DownloadSemaphore = new SemaphoreSlim(concurrencyLevel, concurrencyLevel);
27+
this.TargetDirectory = target;
28+
}
29+
30+
public Task DownloadAllAsync(IEnumerable<Emoji> emojis)
31+
{
32+
var ivs = Path.GetInvalidFileNameChars();
33+
var dns = emojis
34+
.GroupBy(xe => xe.GuildId)
35+
.Select(xg => (xg.Key, xg.First().GuildName));
36+
var dirs = new Dictionary<ulong, DirectoryInfo>();
37+
38+
foreach (var xt in dns)
39+
{
40+
var s = $"{xt.Key} - {xt.GuildName}";
41+
s = this.NormalizeString(s, ivs);
42+
s = Path.Combine(this.TargetDirectory.FullName, s);
43+
44+
var di = new DirectoryInfo(s);
45+
dirs[xt.Key] = di;
46+
di.Create();
47+
}
48+
49+
var tasks = new List<Task>();
50+
foreach (var emoji in emojis)
51+
{
52+
var td = dirs[emoji.GuildId];
53+
var tf = Path.Combine(td.FullName, $"{emoji.Name}.png");
54+
55+
tasks.Add(DownloadAsync(emoji, new FileInfo(tf)));
56+
}
57+
58+
return Task.WhenAll(tasks);
59+
}
60+
61+
private async Task DownloadAsync(Emoji emoji, FileInfo targetFile)
62+
{
63+
await this.DownloadSemaphore.WaitAsync();
64+
65+
try
66+
{
67+
using (var res = await this.Http.GetAsync(string.Format(SOURCE_URL, emoji.Id)))
68+
using (var str = await res.Content.ReadAsStreamAsync())
69+
using (var fs = targetFile.Create())
70+
await str.CopyToAsync(fs);
71+
72+
this.LogCompletion(emoji);
73+
}
74+
catch (Exception ex)
75+
{
76+
this.LogFailure(emoji, ex);
77+
}
78+
finally
79+
{
80+
this.DownloadSemaphore.Release();
81+
}
82+
}
83+
84+
private void LogCompletion(Emoji e)
85+
{
86+
if (this.MessageLogged == null)
87+
return;
88+
89+
this.MessageLogged($"Emoji download completed: {e.Name}/{e.Id}");
90+
}
91+
92+
private void LogFailure(Emoji e, Exception ex)
93+
{
94+
if (this.MessageLogged == null)
95+
return;
96+
97+
this.MessageLogged($"FAIL: {e.Name}/{e.Id} ({ex.GetType()}: {ex.Message})");
98+
}
99+
100+
private string NormalizeString(string val, char[] illegals)
101+
{
102+
var x = val.ToCharArray();
103+
var c = false;
104+
for (var i = 0; i < x.Length; i++)
105+
{
106+
if (illegals.Contains(x[i]))
107+
{
108+
c = true;
109+
x[i] = '_';
110+
}
111+
}
112+
if (c)
113+
return new string(x);
114+
return val;
115+
}
116+
117+
public event MessageLoggedEventHandler MessageLogged;
118+
}
119+
}

0 commit comments

Comments
 (0)