Initial commit
This commit is contained in:
97
Program.cs
Normal file
97
Program.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
namespace SpotiGrabber;
|
||||
using SpotifyAPI.Web;
|
||||
using System.Diagnostics;
|
||||
using YoutubeExplode;
|
||||
using YoutubeExplode.Videos.Streams;
|
||||
|
||||
class Program
|
||||
{
|
||||
static SpotifyClient SpotiClient = null!;
|
||||
static YoutubeClient YtClient = new();
|
||||
|
||||
static YouTubeTrackMatcher TrackMatcher = new(YtClient);
|
||||
|
||||
public static string? ExtractSpotifyId(string url)
|
||||
{
|
||||
var match = System.Text.RegularExpressions.Regex.Match(url, @"(?:open\.spotify\.com/|spotify:)(?:intl-[a-z]{2}/)?(?:track|playlist|album)[/:]([a-zA-Z0-9]+)",
|
||||
System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
||||
return match.Success ? match.Groups[1].Value : null;
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
MainAsync(args).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
static async Task MainAsync(string[] args)
|
||||
{
|
||||
string token = File.ReadAllText("token.txt");
|
||||
SpotiClient = new(token);
|
||||
|
||||
if (args.Length == 0)
|
||||
{
|
||||
Console.WriteLine("Please provide spotify link!");
|
||||
return;
|
||||
}
|
||||
|
||||
string spotiString = args[0];
|
||||
string id = ExtractSpotifyId(spotiString)!;
|
||||
|
||||
if (spotiString.Contains("track"))
|
||||
await ExportSingleTrack(id);
|
||||
else if (spotiString.Contains("playlist"))
|
||||
await ExportPlaylist(id);
|
||||
else
|
||||
Console.WriteLine("Link not supported!");
|
||||
}
|
||||
|
||||
static async Task ExportSingleTrack(string id)
|
||||
{
|
||||
var track = await SpotiClient.Tracks.Get(id);
|
||||
await InternalExportTrack(track, $"{track.Artists.First().Name} - {track.Name}");
|
||||
}
|
||||
|
||||
static async Task ExportPlaylist(string id)
|
||||
{
|
||||
var playlist = await SpotiClient.Playlists.Get(id);
|
||||
var trackPage = playlist.Items!;
|
||||
|
||||
Directory.CreateDirectory($"./{playlist.Name}");
|
||||
|
||||
using var semaphore = new SemaphoreSlim(5);
|
||||
var tasks = new List<Task>();
|
||||
int index = 0;
|
||||
|
||||
await foreach (var playlistTrack in SpotiClient.Paginate(trackPage))
|
||||
{
|
||||
if (playlistTrack.Item is not FullTrack track)
|
||||
continue;
|
||||
|
||||
int currentIndex = index++;
|
||||
|
||||
await semaphore.WaitAsync();
|
||||
|
||||
tasks.Add(Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await InternalExportTrack(track,$"./{playlist.Name}/[{currentIndex}] {track.Artists.First().Name} - {track.Name}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphore.Release();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
|
||||
static async Task InternalExportTrack(FullTrack track, string outputName)
|
||||
{
|
||||
var result = (await TrackMatcher.SearchAsync(track, 3)).First();
|
||||
var manifests = await YtClient.Videos.Streams.GetManifestAsync(result.Video.Id);
|
||||
var streamInfo = manifests.GetAudioOnlyStreams().GetWithHighestBitrate();
|
||||
await Process.Start("ffmpeg.exe", $"-hide_banner -i \"{streamInfo.Url}\" -n \"{outputName}.mp3\"").WaitForExitAsync();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user