Skip to content

Instantly share code, notes, and snippets.

@AldeRoberge
Created November 4, 2025 20:33
Show Gist options
  • Select an option

  • Save AldeRoberge/4a70a5e9aeb375fdc84a29abf5e7355e to your computer and use it in GitHub Desktop.

Select an option

Save AldeRoberge/4a70a5e9aeb375fdc84a29abf5e7355e to your computer and use it in GitHub Desktop.
Allows to find a list of YouTube videos based on their titles.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
namespace YouTubeFinder
{
public class Program
{
private static readonly HttpClient httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(15)
};
public static async Task Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("=== YouTube Finder: Web Search Mode ===");
Console.ResetColor();
var videoTitles = new[]
{
"1 critical Blazor mistake to avoid",
"Vertical slice architecture — Patrick God",
"How to catch a cheater with math",
"Macroblank Serpent EP (music)",
"How to deploy your application to Azure using GitHub (Milan)"
};
var results = new List<SearchResult>();
foreach (var title in videoTitles)
{
LogInfo($"Starting search for: \"{title}\"");
var result = await SearchYouTubeViaWebAsync(title);
results.Add(result);
LogSuccess($"Finished: \"{title}\" -> {result.Url ?? "❌ No result"} (confidence {result.Confidence:0.00})");
Console.WriteLine(new string('-', 80));
await Task.Delay(2000); // delay to avoid rate limits
}
LogInfo("All searches complete. Generating JSON output...");
string jsonOutput = JsonSerializer.Serialize(results, new JsonSerializerOptions { WriteIndented = true });
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(jsonOutput);
Console.ResetColor();
}
private static async Task<SearchResult> SearchYouTubeViaWebAsync(string query)
{
var encodedQuery = Uri.EscapeDataString($"{query} site:youtube.com");
var searchUrl = $"https://www.bing.com/search?q={encodedQuery}";
var result = new SearchResult
{
Query = query,
Method = "WebSearch",
Confidence = 0.0,
Notes = ""
};
try
{
LogDebug($"Requesting Bing search for query: {searchUrl}");
using var response = await httpClient.GetAsync(searchUrl);
if (!response.IsSuccessStatusCode)
{
LogError($"Search request failed ({response.StatusCode}) for query: {query}");
result.Notes = $"HTTP error: {response.StatusCode}";
return result;
}
var html = await response.Content.ReadAsStringAsync();
LogDebug($"Downloaded {html.Length} characters of HTML.");
// --- extract both direct and redirect-style links ---
var matches = new List<string>();
// Direct links
matches.AddRange(Regex.Matches(html, @"https://www\.youtube\.com/watch\?v=[\w-]{11}")
.Cast<Match>().Select(m => m.Value));
// Redirected links (Bing uses /l?url=...)
var redirectMatches = Regex.Matches(html, @"\/l\?url=(https%3[a-zA-Z0-9%._\-]+youtube\.com[a-zA-Z0-9%._\-&=?]+)")
.Cast<Match>()
.Select(m => HttpUtility.UrlDecode(m.Groups[1].Value))
.Where(u => u.Contains("youtube.com/watch"))
.ToList();
matches.AddRange(redirectMatches);
var distinctUrls = matches
.Select(u => u.Split('&')[0]) // remove tracking params
.Distinct()
.ToList();
LogInfo($"Found {distinctUrls.Count} YouTube link(s) in search results:");
foreach (var link in distinctUrls)
LogDebug($" ↳ {link}");
if (distinctUrls.Count > 0)
{
result.Url = distinctUrls.First();
result.Confidence = distinctUrls.Count > 3 ? 0.8 : 0.7;
result.MatchTitle = query;
result.Notes = $"Found {distinctUrls.Count} candidate(s); selected top result.";
}
else
{
result.Url = null;
result.Confidence = 0.0;
result.Notes = "No YouTube result found.";
}
}
catch (TaskCanceledException)
{
LogError($"Timeout while searching for \"{query}\"");
result.Notes = "Timeout occurred.";
}
catch (Exception ex)
{
LogError($"Exception while searching for \"{query}\": {ex.Message}");
result.Notes = $"Error: {ex.Message}";
}
return result;
}
// ----- Logging Helpers -----
private static void LogInfo(string message)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine($"[INFO] {DateTime.Now:T} | {message}");
Console.ResetColor();
}
private static void LogDebug(string message)
{
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.WriteLine($"[DEBUG] {DateTime.Now:T} | {message}");
Console.ResetColor();
}
private static void LogSuccess(string message)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"[SUCCESS] {DateTime.Now:T} | {message}");
Console.ResetColor();
}
private static void LogError(string message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"[ERROR] {DateTime.Now:T} | {message}");
Console.ResetColor();
}
}
public class SearchResult
{
public string Query { get; set; }
public string Url { get; set; }
public double Confidence { get; set; }
public string Method { get; set; }
public string MatchTitle { get; set; }
public string PublishDate { get; set; }
public string Notes { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment