public async Task<Response> Download(ISession session, Episode episode, string template, string downloadpath, Quality quality, Format formats,
CancellationToken token, IProgress<DownloadInfo> progress)
{
try
{
string deflangcode = "jpn";
string deflang = "日本語";
Response ret = new Response();
DaiSukiSession s = session as DaiSukiSession;
if (s == null)
return new Response { ErrorMessage = "Invalid Session", Status = ResponseStatus.InvalidArgument };
if (!episode.PluginMetadata.ContainsKey("Url"))
return new Response { ErrorMessage = "Invalid Episode", Status = ResponseStatus.InvalidArgument };
DownloadInfo dp = new DownloadInfo { FileName = TemplateParser.FilenameFromEpisode(episode, quality, template), Format = formats, Percent = 0, Quality = quality };
token.ThrowIfCancellationRequested();
dp.Languages = new List<string>();
dp.Percent = 1;
dp.Status = "Getting Metadata";
progress.Report(dp);
List<string> todeleteFiles = new List<string>();
WebStream ws = await WebStream.Get(episode.PluginMetadata["Url"], null, LibSet[UserAgentS], null, s.cookies.ToCookieCollection(), SocketTimeout, true, null, _info.ProxyFromGlobalRequirements(_global));
if (ws != null && ws.StatusCode == HttpStatusCode.OK)
{
if (!VerifyLogin(ws.Cookies))
SetLoginError(ret);
else
{
StreamReader rd = new StreamReader(ws);
string dta = rd.ReadToEnd();
rd.Dispose();
ws.Dispose();
Match bgn = bgnWrapper.Match(dta);
if (!bgn.Success)
{
ret.ErrorMessage = "Unable to find Daisuki public key";
ret.Status=ResponseStatus.WebError;
return ret;
}
Match flash = flashVars.Match(dta);
if (!flash.Success)
{
ret.ErrorMessage = "Seems this Episode is a YouTube video, unable to download";
ret.Status = ResponseStatus.WebError;
return ret;
}
MatchCollection col = flash2Vars.Matches(flash.Groups["vars"].Value);
Dictionary<string,string> vars=new Dictionary<string, string>();
foreach (Match m in col)
{
if (m.Success)
{
vars.Add(m.Groups["name"].Value, m.Groups["value"].Value);
}
}
if (!vars.ContainsKey("s") || !vars.ContainsKey("country") || !vars.ContainsKey("init"))
{
ret.ErrorMessage = "Some of Daisuki startup variables are missing";
ret.Status = ResponseStatus.WebError;
return ret;
}
token.ThrowIfCancellationRequested();
ws = await WebStream.Get(LibSet[BaseHostS]+bgn.Groups["wrapper"].Value, null, LibSet[UserAgentS], null, s.cookies.ToCookieCollection(), SocketTimeout, true,null, _info.ProxyFromGlobalRequirements(_global));
if (ws == null || ws.StatusCode != HttpStatusCode.OK)
{
ret.ErrorMessage = "Unable to find Daisuki public key";
ret.Status = ResponseStatus.WebError;
ws?.Dispose();
return ret;
}
rd = new StreamReader(ws);
dta = rd.ReadToEnd();
rd.Dispose();
ws.Dispose();
Match mm = publicKey.Match(dta);
if (!mm.Success)
{
ret.ErrorMessage = "Unable to find Daisuki public key";
ret.Status = ResponseStatus.WebError;
return ret;
}
string bld = mm.Groups["key"].Value.Replace("\\n", "");
token.ThrowIfCancellationRequested();
dp.Percent = 2;
progress.Report(dp);
ws = await WebStream.Get(LibSet[BaseHostS] + vars["country"]+"?cashPath="+ (long)((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalMilliseconds), null, LibSet[UserAgentS], null, s.cookies.ToCookieCollection(), SocketTimeout, true, episode.PluginMetadata["Url"], _info.ProxyFromGlobalRequirements(_global));
Country c;
if (ws == null || ws.StatusCode != HttpStatusCode.OK)
{
ret.ErrorMessage = "Unable to find Daisuki Country Code";
ret.Status = ResponseStatus.WebError;
ws?.Dispose();
return ret;
}
try
{
XmlSerializer ser = new XmlSerializer(typeof(Country));
c = (Country)ser.Deserialize(ws);
ws.Dispose();
}
catch (Exception)
{
ret.ErrorMessage = "Unable to find Daisuki Country Code";
ret.Status = ResponseStatus.WebError;
ws.Dispose();
return ret;
}
Dictionary<string, string> form = new Dictionary<string, string>();
Api api=new Api();
if (vars.ContainsKey("ss_id"))
api.SS_Id = vars["ss_id"];
if (vars.ContainsKey("mv_id"))
api.MV_Id = vars["mv_id"];
if (vars.ContainsKey("device_cd"))
api.Device_CD = vars["device_cd"];
if (vars.ContainsKey("ss1_prm"))
api.SS1_PRM = vars["ss1_prm"];
if (vars.ContainsKey("ss2_prm"))
api.SS2_PRM = vars["ss2_prm"];
if (vars.ContainsKey("ss3_prm"))
api.SS3_PRM = vars["ss3_prm"];
RSACryptoServiceProvider prov = ProviderFromPEM(bld);
AesManaged aes = new AesManaged();
aes.GenerateKey();
aes.Mode=CipherMode.CBC;
int blocksize = aes.BlockSize/8;
aes.IV=new byte[blocksize];
aes.KeySize=256;
aes.Padding=PaddingMode.Zeros;
aes.GenerateKey();
byte[] apidata = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(api));
int nsize = ((apidata.Length + (blocksize - 1))/blocksize)*blocksize;
if (nsize!=apidata.Length)
Array.Resize(ref apidata,nsize);
ICryptoTransform t=aes.CreateEncryptor();
byte[] enc=t.TransformFinalBlock(apidata, 0, nsize);
byte[] key = prov.Encrypt(aes.Key,false);
form.Add("s", vars["s"]);
form.Add("c", c.CountryCode);
form.Add("e", episode.PluginMetadata["Url"]);
form.Add("d", Convert.ToBase64String(enc));
form.Add("a", Convert.ToBase64String(key));
token.ThrowIfCancellationRequested();
string n = form.PostFromDictionary();
ws = await WebStream.Get(LibSet[BaseHostS]+vars["init"]+"?"+n, null, LibSet[UserAgentS], null, s.cookies.ToCookieCollection(), SocketTimeout, true, episode.PluginMetadata["Url"], _info.ProxyFromGlobalRequirements(_global));
if (ws == null || ws.StatusCode != HttpStatusCode.OK)
{
ret.ErrorMessage = "Unable to retrieve metadata";
ret.Status = ResponseStatus.WebError;
ws?.Dispose();
return ret;
}
rd = new StreamReader(ws);
dta = rd.ReadToEnd();
rd.Dispose();
ws.Dispose();
MetaEncrypt menc = JsonConvert.DeserializeObject<MetaEncrypt>(dta);
if (menc == null || menc.Status != "00")
{
ret.ErrorMessage = "Unable to retrieve metadata";
ret.Status = ResponseStatus.WebError;
return ret;
}
t = aes.CreateDecryptor();
byte[] indata = Convert.FromBase64String(menc.EncryptedData);
nsize = ((indata.Length + (blocksize - 1)) / blocksize) * blocksize;
if (nsize != indata.Length)
Array.Resize(ref indata, nsize);
byte[] outdata=t.TransformFinalBlock(indata, 0, indata.Length);
int start = outdata.Length;
while (outdata[start - 1] == 0)
start--;
if (start!=outdata.Length)
Array.Resize(ref outdata,start);
string final = Encoding.UTF8.GetString(outdata);
Data ldta = JsonConvert.DeserializeObject<Data>(final);
NameValueCollection headers = new NameValueCollection();
headers.Add("Accept", "*/*");
headers.Add("Accept-Language", "en-US");
headers.Add("x-flash-version", "18,0,0,232");
string guid = GenGUID(12);
string playurl = ldta.play_url + "&g=" + guid + "&hdcore=3.2.0";
token.ThrowIfCancellationRequested();
dp.Percent = 3;
dp.Status = "Gettings subtitles";
progress.Report(dp);
dp.Languages = new List<string>();
Dictionary<string, string> subtitles = new Dictionary<string, string>();
if (string.IsNullOrEmpty(ldta.caption_url))
dp.Languages.Add("Hardcoded");
else
{
ws = await WebStream.Get(ldta.caption_url + "?cashPath=" + (long)((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalMilliseconds), null, LibSet[UserAgentS], headers, null, SocketTimeout, true, "http://img.daisuki.net/common2/pages/anime/swf/bngn_player_001.swf", _info.ProxyFromGlobalRequirements(_global));
if (ws == null || ws.StatusCode != HttpStatusCode.OK)
{
ret.ErrorMessage = "Unable to retrieve subtitles";
ret.Status = ResponseStatus.WebError;
ws?.Dispose();
return ret;
}
TTML subs = new TTML(ws);
subtitles = subs.ToAss();
ws.Dispose();
}
dp.Percent = 4;
dp.Status = "Downloading video";
progress.Report(dp);
token.ThrowIfCancellationRequested();
ws = await WebStream.Get(playurl, null, LibSet[UserAgentS], headers, null, SocketTimeout, true, "http://img.daisuki.net/common2/pages/anime/swf/bngn_player_001.swf", _info.ProxyFromGlobalRequirements(_global));
int idx = playurl.LastIndexOf(".smil/", StringComparison.InvariantCulture);
string baseurl = string.Empty;
if (idx > 0)
baseurl = playurl.Substring(0, idx + 6);
if (ws == null || ws.StatusCode != HttpStatusCode.OK)
{
ret.ErrorMessage = "Unable to retrieve metadata";
ret.Status = ResponseStatus.WebError;
ws?.Dispose();
return ret;
}
XmlSerializer serm = new XmlSerializer(typeof(Manifest));
//Stream ms = File.OpenRead(@"C:\users\mpiva\Downloads\s.manifest");
//Manifest manifest = (Manifest)serm.Deserialize(ms);
Manifest manifest = (Manifest)serm.Deserialize(ws);
rd.Dispose();
ws.Dispose();
manifest.Init();
KeyValuePair<Media, Quality>? kv = BestMediaFromManifest(manifest, quality);
if (kv == null)
{
ret.ErrorMessage = "Unable to find the best media";
ret.Status = ResponseStatus.WebError;
return ret;
}
dp.Quality = kv.Value.Value;
Media media = kv.Value.Key;
string inputs = string.Empty;
string maps = String.Empty;
int pp = 0;
foreach (string k in subtitles.Keys)
{
string pth = Path.GetTempFileName() + ".ass";
todeleteFiles.Add(pth);
File.WriteAllText(pth, subtitles[k]);
inputs += "-i \"" + pth + "\" ";
dp.Languages.Add(Languages.TranslateToOriginalLanguage(k));
maps += GetFFMPEGSubtitleArguments(pp + 1, pp, Languages.CodeFromLanguage(k), Languages.TranslateToOriginalLanguage(k));
pp++;
}
dp.Percent = 4;
dp.FileName = TemplateParser.FilenameFromEpisode(episode, dp.Quality, template);
dp.FullPath = Path.Combine(downloadpath, dp.FileName);
token.ThrowIfCancellationRequested();
progress.Report(dp);
string intermediatefile = dp.FullPath + ".tm1";
/* http://www.daisuki.net/etc/designs/daisuki/swf/bngn_player_002.swf*/
headers["X-Requested-With"] = "ShockwaveFlash/20.0.0.267";
FragmentProcessor frag =new FragmentProcessor(ws.Cookies,headers, LibSet[UserAgentS], SocketTimeout, episode.PluginMetadata["Url"], _info.ProxyFromGlobalRequirements(_global), 2,5,intermediatefile);
double dbl = 91;
IProgress<double> d = new Progress<double>((val) =>
{
dp.Percent = (val * dbl / 100) + 4;
progress.Report(dp);
});
todeleteFiles.Add(intermediatefile);
await frag.Start(baseurl, guid, manifest, media, token, d);
dp.Size = await ReMux(intermediatefile, inputs, maps, formats, deflangcode, deflang, 96, 4, dp, progress, token);
dp.Percent = 100;
dp.Status = "Finished";
progress.Report(dp);
foreach (string del in todeleteFiles)
{
try
{
File.Delete(del);
}
catch (Exception)
{
}
}
ret.Status = ResponseStatus.Ok;
}
}
else
{
SetWebError(ret);
}
ws?.Dispose();
return ret;
}
catch (Exception e)
{
if (e is OperationCanceledException)
return new Response { ErrorMessage = "Canceled", Status = ResponseStatus.Canceled };
return new Shows { ErrorMessage = e.ToString(), Status = ResponseStatus.SystemError };
}
}