Created
December 19, 2018 11:49
-
-
Save holly-hacker/174a61c526dff4c166f9c20f8eab7054 to your computer and use it in GitHub Desktop.
KHInsider downloader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.IO; | |
using System.Net; | |
using System.Text.RegularExpressions; | |
using System.Threading.Tasks; | |
using Newtonsoft.Json; | |
namespace KHDownload | |
{ | |
internal static class Program | |
{ | |
private static readonly Regex RegexJs = new Regex(@"<script>(eval[\s\S]*?)<\/script>\s+<h2>(.*?)</h2>"); | |
private static readonly Regex RegexParams = new Regex(@"}\('(.+)',(\d+),(\d+),'([^']+)'\.split\('\|'\)"); | |
private static readonly Regex RegexTracks = new Regex(@"mediaPath=\\'(.*?)\\',extension=\\'\\',tracks=\[(.*?),\],trackCount="); | |
private static void Main() | |
{ | |
while (true) { | |
Console.Write("URL: "); | |
string url = Console.ReadLine(); | |
DoDownload(url); | |
Console.WriteLine("Finished downloading."); | |
Console.WriteLine(); | |
} | |
} | |
private static void DoDownload(string url) | |
{ | |
string albumSource = new WebClient().DownloadString(url); | |
var matchJs = RegexJs.Match(albumSource); | |
string js = matchJs.Groups[1].Value.Trim().TrimEnd(';').TrimEnd(); | |
string albumName = matchJs.Groups[2].Value; | |
var args = RegexParams.Match(js); // could pass RegexParams immediately | |
string obfCode = args.Groups[1].Value; | |
int keyspace = int.Parse(args.Groups[2].Value); | |
int stringsLen = int.Parse(args.Groups[3].Value); | |
string[] strings = args.Groups[4].Value.Split('|'); | |
Debug.Assert(keyspace == 62); | |
Debug.Assert(stringsLen == strings.Length); | |
var unpackedJs = Unpack(obfCode, strings); | |
var matchTracks = RegexTracks.Match(unpackedJs); | |
string mediaPath = matchTracks.Groups[1].Value; | |
string tracksJson = "[" + matchTracks.Groups[2].Value + "]"; | |
var tracks = JsonConvert.DeserializeObject<TrackModel[]>(tracksJson); | |
Console.WriteLine($"Found {tracks.Length} tracks"); | |
Directory.CreateDirectory(albumName); | |
Parallel.ForEach(tracks, tr => | |
{ | |
string fileName = tr.Track + ". " + WebUtility.HtmlDecode(tr.Name); | |
if (!fileName.EndsWith(".mp3")) fileName += ".mp3"; | |
string filePath = Path.Combine(albumName, fileName); | |
if (File.Exists(filePath)) { | |
Console.WriteLine($"Skipping {fileName} because it already exists!"); | |
} else { | |
new WebClient().DownloadFile(mediaPath + tr.File, filePath); | |
Console.WriteLine($"Downloaded {fileName}"); | |
} | |
}); | |
} | |
private static string Unpack(string codeParam, string[] strings) | |
{ | |
var dic = new Dictionary<string, string>(); | |
for (int i = strings.Length - 1; i >= 0; i--) { | |
string key = Base62(i); | |
dic[key] = !string.IsNullOrEmpty(strings[i]) ? strings[i] : key; | |
} | |
return Regex.Replace(codeParam, @"\b\w+\b", match => dic[match.Value], RegexOptions.ECMAScript); | |
string Base62(int c) | |
{ | |
const string keyspace = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
string recursive = c < keyspace.Length ? string.Empty : Base62(c / keyspace.Length); | |
return recursive + keyspace[c % keyspace.Length]; | |
} | |
} | |
private class TrackModel | |
{ | |
public string Track, Name, Length, File; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment