Skip to content

Commit

Permalink
v1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
rlaphoenix committed May 30, 2019
1 parent a2d1e07 commit ee549db
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 82 deletions.
48 changes: 38 additions & 10 deletions ISRCDB.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
Expand All @@ -12,7 +13,7 @@ class ISRCDB {

/* API Settings */
private const string API_Endpoint = "https://isrcsearch.ifpi.org/";
private const int API_ResultsPerPage = 10;
private const int API_ResultsPerPage = 100;

public static void GenerateSession() {
if (string.IsNullOrEmpty(CSRF) || string.IsNullOrEmpty(SESSIONID)) {
Expand All @@ -25,12 +26,14 @@ public static void GenerateSession() {
WC = new WebClient();
}
}
public static void Search(string Artist, string Title = "") {
public static List<(string, string)> Search(string Artist, string Title = "") {
// Make sure we have CSRF and SESSIONID's
GenerateSession();
List<(string, string)> ISRCsToDownload = new List<(string, string)>();
int Start = 0;
ConsoleKey Input = ConsoleKey.NoName;
Logger.Info(" - - - - - - - - - - - - - - - - - - - - - ");
Logger.Info("Next Page: DPAD Right\nPrevious Page: DPAD Left\nTo start a download, copy the ISRC code and press DPAD Down to enter it.");
Logger.Info("Next Page: DPAD Right\nPrevious Page: DPAD Left\nTo download an ISRC from this page, press DPAD Down.\nTo try and download every ISRC returned by the query, press DPAD Up (this can take a while!).");
while (true) {
WC.Headers[HttpRequestHeader.Accept] = "application/json";
WC.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36";
Expand All @@ -48,29 +51,54 @@ public static void Search(string Artist, string Title = "") {
break;
}
Logger.Info("Page " + CurrentPage + "/" + TotalPages);
int l = Start;
foreach (JToken R in Results["displayDocs"]) {
Logger.Info(R["isrcCode"] + " :: " + R["artistName"] + " - " + R["trackTitle"] + " [" + (R["recordingYear"].ToString() != string.Empty ? R["recordingYear"] : "----") + "]" + (R["recordingVersion"].ToString() != string.Empty ? " (" + R["recordingVersion"] + ")" : string.Empty));
string ISRC = R["isrcCode"].ToString();
string ISRC_RegistrantCode = new string(ISRC.Skip(2).Take(3).ToArray());
string ISRC_DesignationCode = new string(ISRC.Skip(7).Take(5).ToArray());
string RArtist = R["artistName"].ToString();
string RTitle = R["trackTitle"].ToString();
string Version = R["recordingVersion"].ToString();
Console.ForegroundColor = (ISRC_RegistrantCode == "UV7" || ISRC_RegistrantCode == "IV2") && RArtist.ToLowerInvariant().Contains(Artist.ToLowerInvariant()) && RTitle.ToLowerInvariant().Contains(Title.ToLowerInvariant()) ? ConsoleColor.White : ConsoleColor.DarkGray;
Console.WriteLine((++l).ToString("000") + " :: " + ISRC + " :: " + RArtist + " - " + RTitle + " [" + (R["recordingYear"].ToString() != string.Empty ? R["recordingYear"] : "----") + "]" + (Version != string.Empty ? " (" + Version + ")" : string.Empty));
Console.ResetColor();
}
Logger.Info(" - - - - - - - - - - - - - - - - - - - - - ");
inputCheck:
ConsoleKey Input = Console.ReadKey().Key;
if(Input != ConsoleKey.UpArrow) {
Input = Console.ReadKey().Key;
}
switch (Input) {
case ConsoleKey.DownArrow:
return;
case ConsoleKey.RightArrow:
Logger.Info("[Which ISRC do you want to download? (#)]: ");
JToken SelectedRelease = Results["displayDocs"][int.Parse(Console.ReadLine()) - 1];
return new List<(string, string)> { (SelectedRelease["isrcCode"].ToString(), SelectedRelease["recordingVersion"].ToString()) };
case ConsoleKey.UpArrow:
if(Start == (Total - API_ResultsPerPage)) {
return ISRCsToDownload;
}
ISRCsToDownload.AddRange(Results["displayDocs"].Select(x => new ValueTuple<string, string>(x["isrcCode"].ToString(), x["recordingVersion"].ToString())).ToArray());
Program.DeleteConsoleLines(Results["displayDocs"].Count() + 3);
Start += API_ResultsPerPage;
break;
case ConsoleKey.RightArrow:
if(Start != (Total - API_ResultsPerPage)) {
Program.DeleteConsoleLines(Results["displayDocs"].Count() + 3);
Start += API_ResultsPerPage;
}
break;
case ConsoleKey.LeftArrow:
Program.DeleteConsoleLines(Results["displayDocs"].Count() + 3);
Start -= API_ResultsPerPage;
if(Start != 0) {
Program.DeleteConsoleLines(Results["displayDocs"].Count() + 3);
Start -= API_ResultsPerPage;
}
break;
default:
Program.DeleteCurrentLine();
goto inputCheck;
}

}
return null;
}
}
}
120 changes: 61 additions & 59 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ static void Main(string[] args) {

while(true) {

List<(string ISRC, string Version)> Releases = null;

Console.Write("[Search for an ISRC? (y/n)]: ");
ConsoleKey Input = Console.ReadKey().Key;
DeleteCurrentLine();
Expand All @@ -27,72 +29,73 @@ static void Main(string[] args) {
string Artist = Console.ReadLine();
Console.Write("[Title]: ");
string Title = Console.ReadLine();
ISRCDB.Search(Artist, Title);
Releases = ISRCDB.Search(Artist, Title);
} else {
bool InvalidISRC = false;
do {
if (InvalidISRC) {
Logger.Error(Releases.First().ISRC + " is an invalid ISRC string...");
}
Console.Write("[ISRC]: ");
Releases = new List<(string, string)> { (Console.ReadLine().ToUpperInvariant(), string.Empty) };
DeleteConsoleLines(1);
} while (Releases == null || (InvalidISRC = !Regex.Match(Releases.First().ISRC, "^[A-Z]{2}-?\\w{3}-?\\d{2}-?\\d{5}$").Success));
}

#region Obtain an ISRC from the User
string ISRC = string.Empty; //USUV70900886
bool InvalidISRC = false;
do {
if(InvalidISRC) {
Logger.Error(ISRC + " is an invalid ISRC string...");
foreach ((string ISRC, string Version) Release in Releases) {
string ISRC = Release.ISRC;
string Version = VEVO.Sanitize(Release.Version);
#region Attempt to Query the ISRC to VEVO
if (!VEVO.Query(ISRC)) {
continue;
}
Console.Write("[ISRC]: ");
ISRC = Console.ReadLine().ToUpperInvariant();
DeleteConsoleLines(1);
} while (InvalidISRC = !Regex.Match(ISRC, "^[A-Z]{2}-?\\w{3}-?\\d{2}-?\\d{5}$").Success);
#endregion
#region Attempt to Query the ISRC to VEVO
if (!VEVO.Query(ISRC)) {
continue;
}
#endregion
#region Download HLS Catalogue to MKV File
string Filename = VEVO.Artist + " - " + VEVO.Title;
string HLSCatalogue = VEVO.HLSCatalogue;
Logger.Info(" :=: Downloading " + ISRC + " as \"" + Filename + ".mkv\" :=:");
#region Subtitles
if(!string.IsNullOrEmpty(VEVO.Subtitle)) {
#region Download Subtitle M3U8 File as a VTT
DownloadM3U8(VEVO.Subtitle, "vtt");
#endregion
#region Fix VTT Subtitle
// For some reason the VTT has a ton of garbage not parsed properly with ffmpeg, no idea who to fault but they manually need to be removed.
// "WEBVTT FILE" line has an odd character in front of it, so a .EndsWith is needed.
// The timestamp line may be specific to each video im not sure.
File.WriteAllLines("temp/.vtt", File.ReadAllLines("temp/.vtt", Encoding.UTF8).Select(l => l.Trim()).Where(l => l != "WEBVTT" && !l.EndsWith("WEBVTT FILE") && l != "X-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000"), Encoding.UTF8);
#endregion
#region Convert VTT to SRT
if (RunEXE("SubtitleEdit.exe", "/convert \"temp/.vtt\" srt /overwrite") != 0) {
Logger.Error("Failed to convert the VTT subtitles to SRT, ignoring subtitles and continuing without them!");
if (File.Exists("temp/.vtt")) {
File.Delete("temp/.vtt");
}
if (File.Exists("temp/.srt")) {
File.Delete("temp/.srt");
#region Download HLS Catalogue to MKV File
string Filename = VEVO.Artist + " - " + VEVO.Title + (Version != string.Empty ? " [" + Version + "]" : string.Empty) + " [" + ISRC + "]";
string HLSCatalogue = VEVO.HLSCatalogue;
Logger.Info(" :=: Downloading " + ISRC + " as \"" + Filename + ".mkv\" :=:");
#region Subtitles
if (!string.IsNullOrEmpty(VEVO.Subtitle)) {
#region Download Subtitle M3U8 File as a VTT
DownloadM3U8(VEVO.Subtitle, "vtt");
#endregion
#region Fix VTT Subtitle
// For some reason the VTT has a ton of garbage not parsed properly with ffmpeg, no idea who to fault but they manually need to be removed.
// "WEBVTT FILE" line has an odd character in front of it, so a .EndsWith is needed.
// The timestamp line may be specific to each video im not sure.
File.WriteAllLines("temp/.vtt", File.ReadAllLines("temp/.vtt", Encoding.UTF8).Select(l => l.Trim()).Where(l => l != "WEBVTT" && !l.EndsWith("WEBVTT FILE") && l != "X-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000"), Encoding.UTF8);
#endregion
#region Convert VTT to SRT
if (RunEXE("SubtitleEdit.exe", "/convert \"temp/.vtt\" srt /overwrite") != 0) {
Logger.Error("Failed to convert the VTT subtitles to SRT, ignoring subtitles and continuing without them!");
if (File.Exists("temp/.vtt")) {
File.Delete("temp/.vtt");
}
if (File.Exists("temp/.srt")) {
File.Delete("temp/.srt");
}
}
#endregion
}
#endregion
#region TS (Video/Audio)
DownloadM3U8(VEVO.TS);
#endregion
#region Mux everything into an MKV
if (RunEXE("mkvmerge.exe", "--output \"" + Path.Combine(ROOTDIR, Filename.Replace("/", "-") + ".mkv") + "\" \"" + Path.Combine(ROOTDIR, "temp", ".ts") + "\" --default-track 0:false " + (File.Exists("temp/.chapters") ? "--chapters \"" + Path.Combine(ROOTDIR, "temp", ".chapters") + "\"" : string.Empty) + " " + (File.Exists("temp/.srt") ? "--sub-charset 0:UTF-8 \"" + Path.Combine(ROOTDIR, "temp", ".srt") + "\"" : string.Empty)) != 0) {
return;
}
// Cleanup files no longer needed
// todo: setup files in such a way to be multi-threaded supported and not conflict with other downloads at same time
File.Delete("temp/.ts");
File.Delete("temp/.srt");
File.Delete("temp/.chapters");
#endregion
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Downloaded!");
Console.ResetColor();
#endregion
}
#endregion
#region TS (Video/Audio)
DownloadM3U8(VEVO.TS);
#endregion
#region Mux everything into an MKV
Logger.Info("Using MKVMERGE to mux everything to a single MKV file");
if (RunEXE("mkvmerge.exe", "--output \"" + Path.Combine(ROOTDIR, Filename.Replace("/", "-") + ".mkv") + "\" \"" + Path.Combine(ROOTDIR, "temp", ".ts") + "\" --default-track 0:false " + (File.Exists("temp/.chapters") ? "--chapters \"" + Path.Combine(ROOTDIR, "temp", ".chapters") + "\"" : string.Empty) + " " + (File.Exists("temp/.srt") ? "--sub-charset 0:UTF-8 \"" + Path.Combine(ROOTDIR, "temp", ".srt") + "\"" : string.Empty)) != 0) {
return;
}
// Cleanup files no longer needed
// todo: setup files in such a way to be multi-threaded supported and not conflict with other downloads at same time
File.Delete("temp/.ts");
File.Delete("temp/.srt");
File.Delete("temp/.chapters");
#endregion
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Downloaded!");
Console.ResetColor();
#endregion

}
}
Expand Down Expand Up @@ -130,7 +133,6 @@ private static int RunEXE(string exePath, string args) {
return p.ExitCode;
}
private static void DownloadM3U8(string URL, string Type = "ts") {
Logger.Info("Downloading M3U8 " + Type.ToUpperInvariant() + " Segments in a Multi-Threaded environment to Segments Folder");
foreach (string dir in new[] { "temp", "temp/seg" }) {
Directory.CreateDirectory(dir);
}
Expand Down
2 changes: 1 addition & 1 deletion Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]
32 changes: 20 additions & 12 deletions VEVO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
namespace vevodl {
class VEVO {
#region Public Properties
public static JToken Metadata => _Query["basicMeta"];
public static JToken Streams => _Query["streams"];
public static string Artist => Metadata["artists"].First(x => x["basicMeta"]["role"].ToString() == "Main")["basicMeta"]["name"].ToString();
public static string Title => Metadata["title"].ToString();
public static string HLSCatalogue => new WebClient().DownloadString(Streams.Where(x => x["url"].ToString().ToLowerInvariant().EndsWith(".m3u8")).First()["url"].ToString());
public static string Subtitle => Regex.Match(HLSCatalogue, "#EXT-X-MEDIA:TYPE=SUBTITLES.*?,URI=\"([^\"]*)").Groups[1].Value;
public static string TS => Regex.Matches(HLSCatalogue, "#EXT-X-STREAM.*?BANDWIDTH=([^,]*),RESOLUTION=[^x]*x([^,]*).*\\s(.*)").Cast<Match>().OrderByDescending(x => int.Parse(x.Groups[1].Value)).OrderByDescending(x => int.Parse(x.Groups[2].Value)).First().Groups[3].Value;
public static string Sanitize(string Input) => Regex.Replace(Input, "[!?,'*():]", x => string.Empty);
public static string Artist { get; private set; }
public static string Title { get; private set; }
public static string HLSCatalogue { get; private set; }
public static string Subtitle { get; private set; }
public static string TS { get; private set; }
#endregion
#region Token
private static string _Token = null;
Expand Down Expand Up @@ -42,14 +41,23 @@ public static bool Query(string ISRC) {
WC.Headers["Vevo-OS"] = "Windows/10";
WC.Headers["Vevo-Product"] = "web-syndication/0";
WC.Headers[HttpRequestHeader.Authorization] = "Bearer " + Token();
JToken Result = JToken.Parse(WC.UploadString("https://veil.vevoprd.com/graphql", "{\"query\":\"query Video($ids: [String]!, $partnerId: String) {\\n videos(ids: $ids, partnerId: $partnerId) {\\n data {\\n id\\n basicMeta {\\n artists {\\n basicMeta {\\n name\\n role\\n urlSafeName\\n thumbnailUrl\\n links {\\n url\\n userName\\n type\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n isMonetizable\\n isrc\\n title\\n urlSafeTitle\\n copyright\\n shortUrl\\n thumbnailUrl\\n duration\\n hasLyrics\\n allowEmbed\\n allowMobile\\n isUnlisted\\n isOfficial\\n releaseDate\\n categories\\n credits {\\n name\\n value\\n __typename\\n }\\n errorCode\\n __typename\\n }\\n likes\\n liked\\n views {\\n viewsTotal\\n __typename\\n }\\n streams {\\n quality\\n url\\n errorCode\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n}\\n\",\"variables\":{\"ids\":[\"" + ISRC.ToLowerInvariant() + "\"]},\"operationName\":\"Video\"}"))["data"]["videos"]["data"][0];
if (Result["streams"][0]["errorCode"].ToString() == "404") {
_Query = JToken.Parse(WC.UploadString("https://veil.vevoprd.com/graphql", "{\"query\":\"query Video($ids: [String]!, $partnerId: String) {\\n videos(ids: $ids, partnerId: $partnerId) {\\n data {\\n id\\n basicMeta {\\n artists {\\n basicMeta {\\n name\\n role\\n urlSafeName\\n thumbnailUrl\\n links {\\n url\\n userName\\n type\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n isMonetizable\\n isrc\\n title\\n urlSafeTitle\\n copyright\\n shortUrl\\n thumbnailUrl\\n duration\\n hasLyrics\\n allowEmbed\\n allowMobile\\n isUnlisted\\n isOfficial\\n releaseDate\\n categories\\n credits {\\n name\\n value\\n __typename\\n }\\n errorCode\\n __typename\\n }\\n likes\\n liked\\n views {\\n viewsTotal\\n __typename\\n }\\n streams {\\n quality\\n url\\n errorCode\\n __typename\\n }\\n __typename\\n }\\n __typename\\n }\\n}\\n\",\"variables\":{\"ids\":[\"" + ISRC.ToLowerInvariant() + "\"]},\"operationName\":\"Video\"}"))["data"]["videos"]["data"][0];
JToken Metadata = _Query["basicMeta"];
JToken Streams = _Query["streams"];
if (Metadata["errorCode"].ToString() == "404") {
Console.WriteLine(ISRC + " isn't available on VEVO's Systems...");
return false;
}
//Logger.Error("Failed to Query ISRC of " + ISRC + " on VEVO's Servers. Retrying in 5 seconds...");
//Thread.Sleep(5000);
_Query = Result;
try {
Artist = Sanitize(Metadata["artists"].First(x => x["basicMeta"]["role"].ToString() == "Main")["basicMeta"]["name"].ToString());
Title = Sanitize(Metadata["title"].ToString());
HLSCatalogue = new WebClient().DownloadString(Streams.Where(x => x["url"].ToString().ToLowerInvariant().EndsWith(".m3u8")).First()["url"].ToString());
Subtitle = Regex.Match(HLSCatalogue, "#EXT-X-MEDIA:TYPE=SUBTITLES.*?,URI=\"([^\"]*)").Groups[1].Value;
TS = Regex.Matches(HLSCatalogue, "#EXT-X-STREAM.*?BANDWIDTH=([^,]*).*?,RESOLUTION=[^x]*x([^,\n]*).*\\s(.*)").Cast<Match>().OrderByDescending(x => int.Parse(x.Groups[1].Value)).OrderByDescending(x => int.Parse(x.Groups[2].Value)).First().Groups[3].Value;
} catch {
Logger.Error("Something went wrong on VEVO's end for ISRC " + ISRC + " :(");
return false;
}
}
return true;
}
Expand Down

0 comments on commit ee549db

Please sign in to comment.