Skip to content

Commit

Permalink
[CastIt] Minor improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Wolfteam committed Aug 22, 2020
1 parent ad24ba7 commit dbaad54
Show file tree
Hide file tree
Showing 17 changed files with 266 additions and 234 deletions.
110 changes: 56 additions & 54 deletions CastIt/Common/Utils/YoutubeUrlDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Web;

Expand Down Expand Up @@ -67,15 +68,15 @@ public async Task<YoutubeMedia> Parse(string url, int quality)
_logger.Info($"{nameof(Parse)}: Trying to parse url = {url}");
var media = new YoutubeMedia();
using var httpClient = new HttpClient();
var response = await httpClient.GetAsync(url);
var response = await httpClient.GetAsync(url).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
return media;

var body = await response.Content.ReadAsStringAsync();
var body = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
if (body.Contains(TitleKeyWord))
{
// video title
int titleStart = body.IndexOf(TitleKeyWord);
int titleStart = body.IndexOf(TitleKeyWord, StringComparison.OrdinalIgnoreCase);
var title = new StringBuilder();
char ch;
do
Expand All @@ -90,7 +91,7 @@ public async Task<YoutubeMedia> Parse(string url, int quality)
if (body.Contains(DescriptionKeyWord))
{
// video description
int descStart = body.IndexOf(DescriptionKeyWord);
int descStart = body.IndexOf(DescriptionKeyWord, StringComparison.Ordinal);
var desc = new StringBuilder();
char ch;
do
Expand All @@ -105,24 +106,24 @@ public async Task<YoutubeMedia> Parse(string url, int quality)
if (body.Contains(ThumbnailKeyWord))
{
// video thumbnail
int thumbnailStart = body.IndexOf(ThumbnailKeyWord);
StringBuilder thumbnailURL = new StringBuilder();
int thumbnailStart = body.IndexOf(ThumbnailKeyWord, StringComparison.OrdinalIgnoreCase);
var thumbnailUrl = new StringBuilder();
char ch;
do
{
ch = body[thumbnailStart++];
thumbnailURL.Append(ch);
thumbnailUrl.Append(ch);
}
while (ch != '>');
media.ThumbnailUrl = GetKeyContentValue(thumbnailURL.ToString());
media.ThumbnailUrl = GetKeyContentValue(thumbnailUrl.ToString());
}

if (body.Contains(UrlEncodedStreamMap))
{
// find the string we are looking for
int start = body.IndexOf(UrlEncodedStreamMap) + UrlEncodedStreamMap.Length + 1; // is the opening "
int start = body.IndexOf(UrlEncodedStreamMap, StringComparison.OrdinalIgnoreCase) + UrlEncodedStreamMap.Length + 1; // is the opening "
string urlMap = body.Substring(start);
int end = urlMap.IndexOf("\"");
int end = urlMap.IndexOf("\"", StringComparison.Ordinal);
if (end > 0)
{
urlMap = urlMap.Substring(0, end);
Expand All @@ -133,14 +134,14 @@ public async Task<YoutubeMedia> Parse(string url, int quality)
if (body.Contains(YoutubePlayerConfig))
{
body = body.Replace("\\/", "/");
int start = body.IndexOf(YoutubePlayerConfig);
int start = body.IndexOf(YoutubePlayerConfig, StringComparison.OrdinalIgnoreCase);
string playerConfig = body.Substring(start);
playerConfig = playerConfig
.Substring(0, playerConfig.IndexOf("</script>"))
.Substring(0, playerConfig.IndexOf("</script>", StringComparison.OrdinalIgnoreCase))
.Replace("\\/", "/");
var jsMatch = Regex.Match(playerConfig, "(\"js\":.*?.js)");
string jsUrl = jsMatch.Value;
jsUrl = YoutubeUrl + jsUrl.Substring(jsUrl.IndexOf("/"));
jsUrl = YoutubeUrl + jsUrl.Substring(jsUrl.IndexOf("/", StringComparison.Ordinal));

var formatPattern = @"(\\""formats\\"":\[.*?])";
var formatMatch = Regex.Match(body, formatPattern);
Expand All @@ -164,7 +165,7 @@ public async Task<YoutubeMedia> Parse(string url, int quality)
string cipher = Regex.Match(pick, cipherPattern).Value;
if (string.IsNullOrEmpty(cipher))
{
_logger.Info($"{nameof(Parse)}: Url doesnt contain a cipher...");
_logger.Info($"{nameof(Parse)}: Url doesn't contain a cipher...");
//Unscrambled signature, already included in ready-to-use URL
string urlPattern = @"(?<=url\\"":\\"").*?(?=\\"")";
media.Url = DecodeUrlString(Regex.Match(pick, urlPattern).Value);
Expand All @@ -173,7 +174,7 @@ public async Task<YoutubeMedia> Parse(string url, int quality)
{
_logger.Info($"{nameof(Parse)}: Url contains a cipher...");
//Scrambled signature: some assembly required
media.Url = await GetUrlFromCipher(cipher, jsUrl);
media.Url = await GetUrlFromCipher(cipher, jsUrl).ConfigureAwait(false);
}
}

Expand All @@ -182,7 +183,7 @@ public async Task<YoutubeMedia> Parse(string url, int quality)
return media;
}

public async Task<List<string>> ParseYouTubePlayList(string url)
public async Task<List<string>> ParseYouTubePlayList(string url, CancellationToken token)
{
var links = new List<string>();
_logger.Info($"{nameof(ParseYouTubePlayList)}: Parsing url = {url}");
Expand All @@ -197,7 +198,7 @@ public async Task<List<string>> ParseYouTubePlayList(string url)
}

using var httpClient = new HttpClient();
var response = await httpClient.GetAsync(url).ConfigureAwait(false);
var response = await httpClient.GetAsync(url, token).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
_logger.Warn($"{nameof(ParseYouTubePlayList)}: Response is not success status code. Code = {response.StatusCode}");
Expand All @@ -216,7 +217,7 @@ public async Task<List<string>> ParseYouTubePlayList(string url)
links = table.Descendants("a")
.Where(node => node.HasClass("pl-video-title-link"))
.Select(node => RemoveNotNeededParams(YoutubeUrl + node.GetAttributeValue("href", string.Empty)))
.Where(link => link.StartsWith(YoutubeUrl))
.Where(link => link.StartsWith(YoutubeUrl, StringComparison.OrdinalIgnoreCase))
.Distinct()
.ToList();
}
Expand All @@ -227,7 +228,7 @@ public async Task<List<string>> ParseYouTubePlayList(string url)
body = body.Replace("\\u0026", "&").Replace("\\/", "/");
links = Regex.Matches(body, pattern)
.Select(match => RemoveNotNeededParams(YoutubeUrl + match.Value))
.Where(link => link.StartsWith(YoutubeUrl))
.Where(link => link.StartsWith(YoutubeUrl, StringComparison.OrdinalIgnoreCase))
.Distinct()
.ToList();
}
Expand All @@ -239,17 +240,15 @@ public async Task<List<string>> ParseYouTubePlayList(string url)
private string GetKeyContentValue(string str)
{
var contentStr = new StringBuilder();
int contentStart = str.IndexOf(ContentValueKeyWord) + ContentValueKeyWord.Length;
if (contentStart > 0)
int contentStart = str.IndexOf(ContentValueKeyWord, StringComparison.OrdinalIgnoreCase) + ContentValueKeyWord.Length;
if (contentStart <= 0)
return contentStr.ToString();
while (true)
{
char ch;
while (true)
{
ch = str[contentStart++];
if (ch == '\"')
break;
contentStr.Append(ch);
}
var ch = str[contentStart++];
if (ch == '\"')
break;
contentStr.Append(ch);
}
return contentStr.ToString();
}
Expand All @@ -258,15 +257,14 @@ private string GetURLEncodedStream(string stream)
{
// replace all the \u0026 with &
string str = DecodeUrlString(stream).Replace("\\u0026", "&");
string urlMap = str.Substring(str.IndexOf("url=http") + 4);
string urlMap = str.Substring(str.IndexOf("url=http", StringComparison.OrdinalIgnoreCase) + 4);
// search urlMap until we see either a & or ,
var sb = new StringBuilder();
for (int i = 0; i < urlMap.Length; i++)
foreach (var t in urlMap)
{
if ((urlMap[i] == '&') || (urlMap[i] == ','))
if (t == '&' || t == ',')
break;
else
sb.Append(urlMap[i]);
sb.Append(t);
}
return sb.ToString();
}
Expand Down Expand Up @@ -297,11 +295,11 @@ private async Task<string> JsDescramble(string s, string jsUrl)
{
//Fetch javascript code
using var httpClient = new HttpClient();
var response = await httpClient.GetAsync(jsUrl);
var response = await httpClient.GetAsync(jsUrl).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
return string.Empty;

string js = await response.Content.ReadAsStringAsync();
string js = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

//Look for the descrambler function's name (in this example its "pt")
//if (k.s) { var l=k.sp, m=pt(decodeURIComponent(k.s)); f.set(l, encodeURIComponent(m))}
Expand All @@ -310,7 +308,7 @@ private async Task<string> JsDescramble(string s, string jsUrl)
//"signature" or "sig") to set with the output, descrambled signature
string descramblerPattern = @"(?<=[,&|]).(=).+(?=\(decodeURIComponent)";
var descramblerMatch = Regex.Match(js, descramblerPattern);
string descrambler = descramblerMatch.Value.Substring(descramblerMatch.Value.IndexOf("=") + 1);
string descrambler = descramblerMatch.Value.Substring(descramblerMatch.Value.IndexOf("=", StringComparison.Ordinal) + 1);

//Fetch the code of the descrambler function
//Go = function(a){ a = a.split(""); Fo.sH(a, 2); Fo.TU(a, 28); Fo.TU(a, 44); Fo.TU(a, 26); Fo.TU(a, 40); Fo.TU(a, 64); Fo.TR(a, 26); Fo.sH(a, 1); return a.join("")};
Expand All @@ -320,7 +318,7 @@ private async Task<string> JsDescramble(string s, string jsUrl)
//Get the name of the helper object providing transformation definitions
string helperPattern = @"(?<=;).*?(?=\.)";
string helper = Regex.Split(Regex.Match(rules, helperPattern).Value, @"\W+")
.GroupBy(s => s)
.GroupBy(g => g)
.OrderByDescending(g => g.Count())
.Select(g => g.Key)
.FirstOrDefault();
Expand Down Expand Up @@ -365,22 +363,26 @@ private async Task<string> JsDescramble(string s, string jsUrl)
string transToApply = x.Split(".".ToCharArray()).Last();

//sH
string transName = transToApply.Substring(0, transToApply.IndexOf("("));
if (trans[transName] == "reverse")
{
s = new string(s.Reverse().ToArray());
}
else if (trans[transName] == "slice")
{
int value = int.Parse(transToApply.Split(commaSeparator).Last().Replace(")", ""));
s = s.Substring(value);
}
else if (trans[transName] == "swap")
string transName = transToApply.Substring(0, transToApply.IndexOf("(", StringComparison.Ordinal));
switch (trans[transName])
{
int value = int.Parse(transToApply.Split(commaSeparator).Last().Replace(")", ""));
var c = s[0];
s = s.ReplaceAt(0, s[value % s.Length]);
s = s.ReplaceAt(value % s.Length, c);
case "reverse":
s = new string(s.Reverse().ToArray());
break;
case "slice":
{
int value = int.Parse(transToApply.Split(commaSeparator).Last().Replace(")", ""));
s = s.Substring(value);
break;
}
case "swap":
{
int value = int.Parse(transToApply.Split(commaSeparator).Last().Replace(")", ""));
var c = s[0];
s = s.ReplaceAt(0, s[value % s.Length]);
s = s.ReplaceAt(value % s.Length, c);
break;
}
}
}

Expand All @@ -398,7 +400,7 @@ private string DecodeUrlString(string url)
private string RemoveNotNeededParams(string url)
{
string videoId = GetVideoId(url);
return url.Substring(0, url.IndexOf("?") + 1) + $"{YoutubeVideoQueryParam}={videoId}";
return url.Substring(0, url.IndexOf("?", StringComparison.Ordinal) + 1) + $"{YoutubeVideoQueryParam}={videoId}";
}

private string GetVideoId(string url)
Expand Down
1 change: 0 additions & 1 deletion CastIt/Interfaces/ICastService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using CastIt.Common;
using CastIt.GoogleCast.Interfaces;
using CastIt.GoogleCast.Models.Media;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
Expand Down
2 changes: 1 addition & 1 deletion CastIt/Interfaces/IFFMpegService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace CastIt.Interfaces
public interface IFFMpegService
{
string GetThumbnail(string mrl, int second);
Task GenerateThumbmnails(string mrl);
Task GenerateThumbnails(string mrl);
void KillThumbnailProcess();
void KillTranscodeProcess();
Task TranscodeVideo(
Expand Down
3 changes: 2 additions & 1 deletion CastIt/Interfaces/IYoutubeUrlDecoder.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using CastIt.Models.Youtube;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace CastIt.Interfaces
Expand All @@ -10,6 +11,6 @@ public interface IYoutubeUrlDecoder
bool IsPlayListAndVideo(string url);
bool IsPlayList(string url);
Task<YoutubeMedia> Parse(string url, int quality);
Task<List<string>> ParseYouTubePlayList(string url);
Task<List<string>> ParseYouTubePlayList(string url, CancellationToken cancellationToken);
}
}
23 changes: 8 additions & 15 deletions CastIt/Server/AppWebServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,24 +181,17 @@ private string GetBaseUrl()

private string GetIpAddress()
{
string localIP = null;
try
string localIp = null;
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
{
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
{
socket.Connect("8.8.8.8", 65530);
var endPoint = socket.LocalEndPoint as IPEndPoint;
localIP = endPoint.Address.ToString();
}
socket.Connect("8.8.8.8", 65530);
var endPoint = socket.LocalEndPoint as IPEndPoint;
localIp = endPoint.Address.ToString();
}

var port = GetOpenPort();
var port = GetOpenPort();

return $"http://{localIP}:{port}";
}
catch (Exception)
{
throw;
}
return $"http://{localIp}:{port}";
}

private int GetOpenPort(int startPort = DefaultPort)
Expand Down
6 changes: 2 additions & 4 deletions CastIt/Server/MediaModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ public MediaModule(

protected override async Task OnRequestAsync(IHttpContext context)
{
var path = context.RequestedPath;
var verb = context.Request.HttpVerb;
var query = context.GetRequestQueryData();
if (query.Count == 0 || !query.AllKeys.All(q => AppWebServer.AllowedQueryParameters.Contains(q)))
{
Expand Down Expand Up @@ -97,7 +95,7 @@ await _ffmpegService.TranscodeVideo(
}
else
{
using var memoryStream = await _ffmpegService.TranscodeMusic(
await using var memoryStream = await _ffmpegService.TranscodeMusic(
filepath,
audioStreamIndex,
seconds,
Expand All @@ -113,7 +111,7 @@ await memoryStream.CopyToAsync(context.Response.OutputStream, _tokenSource.Token
{
if (e is IOException || e is TaskCanceledException)
return;
_logger.Error(e, $"{nameof(OnRequestAsync)}: Unknown error occcured");
_logger.Error(e, $"{nameof(OnRequestAsync)}: Unknown error occurred");
_telemetryService.TrackError(e);
}
finally
Expand Down
Loading

0 comments on commit dbaad54

Please sign in to comment.