Last active
April 28, 2017 03:30
-
-
Save gdkchan/fed0d38eeef241e7d3d243c9e5b788e3 to your computer and use it in GitHub Desktop.
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
/* | |
* This is free and unencumbered software released into the public domain. | |
* | |
* Anyone is free to copy, modify, publish, use, compile, sell, or | |
* distribute this software, either in source code form or as a compiled | |
* binary, for any purpose, commercial or non-commercial, and by any | |
* means. | |
* | |
* In jurisdictions that recognize copyright laws, the author or authors | |
* of this software dedicate any and all copyright interest in the | |
* software to the public domain. We make this dedication for the benefit | |
* of the public at large and to the detriment of our heirs and | |
* successors. We intend this dedication to be an overt act of | |
* relinquishment in perpetuity of all present and future rights to this | |
* software under copyright law. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
* OTHER DEALINGS IN THE SOFTWARE. | |
* | |
* For more information, please refer to <http://unlicense.org/> | |
*/ | |
using System; | |
using System.IO; | |
using System.IO.Compression; | |
using System.Net; | |
using System.Security.Cryptography; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
namespace UnBili | |
{ | |
class Program | |
{ | |
const string UserAgent = "Mozilla / 5.0(Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"; | |
const string AppKey = "6f90a59ac58a4123"; | |
const string BiliKey = "0bfd84cc3940035173f35e6777508326"; | |
static void Main(string[] args) | |
{ | |
Console.WriteLine("Bilibili Stream URL generation test by gdkchan"); | |
Console.WriteLine("Enter a video URL to extract the Stream:"); | |
string URL = Console.ReadLine(); | |
Console.WriteLine(string.Empty); | |
Console.WriteLine("Trying to download the webpage..."); | |
string HTML = HttpGetGZip(URL); | |
string CId = Regex.Match(HTML, "cid=([0-9]*)").Groups[1].Value; | |
//Here we create the JSON URL | |
//We need to generate a signature based on some parameters (see GenSign function for details) | |
string[] Params = new string[6]; | |
Params[0] = "cid=" + CId; | |
Params[1] = "appkey=" + AppKey; | |
Params[2] = "otype=json"; | |
Params[3] = "type=mp4"; | |
Params[4] = "quality=2"; | |
Params[5] = "sign=" + GenSign(CId); | |
string JSONURL = "http://interface.bilibili.com/playurl?" + string.Join("&", Params); | |
Console.WriteLine("Trying to download JSON from \"" + JSONURL + "\"..."); | |
Console.WriteLine(string.Empty); | |
string JSON = HttpGet(JSONURL); | |
//Extract all URLs from the JSON | |
MatchCollection URLs = Regex.Matches(JSON, "https?://[^\"]*"); | |
if (URLs.Count > 0) | |
{ | |
Console.ForegroundColor = ConsoleColor.White; | |
Console.WriteLine("URLs:"); | |
Console.ResetColor(); | |
foreach (Match StreamURL in URLs) | |
{ | |
Console.WriteLine(StreamURL.Value); | |
} | |
} | |
else | |
{ | |
//If we couldn't extract URLs then something is broken, show the returned message | |
Console.WriteLine("Can't extract, see JSON below:" + Environment.NewLine + JSON); | |
} | |
Console.WriteLine(string.Empty); | |
Console.WriteLine("Press any key to exit"); | |
Console.ReadKey(); | |
} | |
static string GenSign(string ContentId) | |
{ | |
//Generates the Signature from a given Video CId | |
/* | |
* Example of a signature before being hashed: | |
* appkey=6f90a59ac58a4123&cid=9388980&otype=json&quality=2&type=mp40bfd84cc3940035173f35e6777508326 | |
* Both keys are constant for a given Player version. When the Player version changes, the base values | |
* for generating the keys or the primitives themselves may change. | |
*/ | |
string[] Params = new string[5]; | |
Params[0] = "appkey=" + AppKey; | |
Params[1] = "cid=" + ContentId; | |
Params[2] = "otype=json"; | |
Params[3] = "quality=2"; | |
Params[4] = "type=mp4"; | |
string BaseSign = string.Join("&", Params) + BiliKey; | |
string Signature = GetMD5(BaseSign); | |
return Signature; | |
} | |
#region "Hash Utils" | |
static string GetMD5(string Input) | |
{ | |
//Calculates the MD5 of a Input string | |
using (MD5 Hash = MD5.Create()) | |
{ | |
//Compute the MD5 Hash of the String on a Byte Array | |
byte[] Hashed = Hash.ComputeHash(Encoding.ASCII.GetBytes(Input)); | |
//Convert Byte Array to a Hex String and returns it | |
StringBuilder Output = new StringBuilder(); | |
foreach (byte HB in Hashed) Output.Append(HB.ToString("X2")); | |
return Output.ToString().ToLowerInvariant(); | |
} | |
} | |
#endregion | |
#region "HTTP Utils" | |
private static string HttpGetGZip(string URL) | |
{ | |
//This just downloads a Webpage using HTTP Get and the Firefox User Agent | |
WebRequest Request = WebRequest.Create(URL); | |
((HttpWebRequest)Request).UserAgent = UserAgent; | |
//Note: The page is GZip compressed, so we need to decompress it first | |
WebResponse Response = Request.GetResponse(); | |
using (GZipStream Reader = new GZipStream(Response.GetResponseStream(), CompressionMode.Decompress)) | |
{ | |
using (MemoryStream Output = new MemoryStream()) | |
{ | |
byte[] Buffer = new byte[0x1000]; //4KiB Buffer | |
int Length = 0; | |
while ((Length = Reader.Read(Buffer, 0, Buffer.Length)) > 0) | |
{ | |
Output.Write(Buffer, 0, Length); | |
} | |
return Encoding.UTF8.GetString(Output.ToArray()); | |
} | |
} | |
} | |
private static string HttpGet(string URL) | |
{ | |
//Same thing of the function above, but without the GZip compression | |
WebRequest Request = WebRequest.Create(URL); | |
((HttpWebRequest)Request).UserAgent = UserAgent; | |
WebResponse Response = Request.GetResponse(); | |
StreamReader Reader = new StreamReader(Response.GetResponseStream()); | |
return Reader.ReadToEnd(); | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment