Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/scrape.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ jobs:
$result | Out-File -FilePath "daily100-$date.json" -Force
popd

- name: Run Spotify app - Daily 100
shell: pwsh
run: |
$date = (Get-Date).ToUniversalTime().AddHours(9).ToString("yyyyMMdd")
# $result = dotnet run --project ./samples/SpotifyPlaylist.ConsoleApp/ -- -t spotify -s ${{ secrets.SPOTIFY_PLAYLIST_ID }} --json | ConvertFrom-Json
$result = dotnet run --project ./samples/SpotifyPlaylist.ConsoleApp/ -- -t spotify -s ${{ secrets.SPOTIFY_PLAYLIST_ID }} --json

mkdir -p ./data
pushd ./data
# $result | ConvertTo-Json -Depth 100 | Out-File -FilePath "spotify100-$date.json" -Force
$result | Out-File -FilePath "spotify100-$date.json" -Force
popd

- name: Upload data
uses: stefanzweifel/git-auto-commit-action@v5
with:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -482,3 +482,7 @@ $RECYCLE.BIN/

# Vim temporary swap files
*.swp

# project specific
appsettings.*.json
!appsettings.*.sample.json
9 changes: 8 additions & 1 deletion MelonChart.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{ACA1
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MelonChart.ConsoleApp", "samples\MelonChart.ConsoleApp\MelonChart.ConsoleApp.csproj", "{FA517387-3495-4649-81D3-AF51A9A683B8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MelonChart.WebApp", "samples\MelonChart.WebApp\MelonChart.WebApp.csproj", "{1515CA58-4FAF-4F89-898C-599E55694F84}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MelonChart.WebApp", "samples\MelonChart.WebApp\MelonChart.WebApp.csproj", "{1515CA58-4FAF-4F89-898C-599E55694F84}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpotifyPlaylist.ConsoleApp", "samples\SpotifyPlaylist.ConsoleApp\SpotifyPlaylist.ConsoleApp.csproj", "{82E64E82-F366-4650-9A66-E15FAF968882}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -39,6 +41,10 @@ Global
{1515CA58-4FAF-4F89-898C-599E55694F84}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1515CA58-4FAF-4F89-898C-599E55694F84}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1515CA58-4FAF-4F89-898C-599E55694F84}.Release|Any CPU.Build.0 = Release|Any CPU
{82E64E82-F366-4650-9A66-E15FAF968882}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{82E64E82-F366-4650-9A66-E15FAF968882}.Debug|Any CPU.Build.0 = Debug|Any CPU
{82E64E82-F366-4650-9A66-E15FAF968882}.Release|Any CPU.ActiveCfg = Release|Any CPU
{82E64E82-F366-4650-9A66-E15FAF968882}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -48,6 +54,7 @@ Global
{48FBE532-F50C-4CE5-A61D-86B5921B9ACE} = {8CF3DBA1-84DB-4274-86EA-3BB54B7262C0}
{FA517387-3495-4649-81D3-AF51A9A683B8} = {ACA1464B-2D70-4B57-B6A6-2E399931AC0A}
{1515CA58-4FAF-4F89-898C-599E55694F84} = {ACA1464B-2D70-4B57-B6A6-2E399931AC0A}
{82E64E82-F366-4650-9A66-E15FAF968882} = {ACA1464B-2D70-4B57-B6A6-2E399931AC0A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {34032734-030B-4982-8F04-9138EFCDF681}
Expand Down
8 changes: 6 additions & 2 deletions samples/MelonChart.ConsoleApp/Services/MelonChartService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,20 @@ namespace MelonChart.ConsoleApp.Services;
/// <param name="charts">List of <see cref="IChart"/> instances.</param>
public class MelonChartService(IEnumerable<IChart> charts) : IMelonChartService
{
private readonly IEnumerable<IChart> _charts = charts ?? throw new ArgumentNullException(nameof(charts));
#pragma warning disable IDE1006 // Naming Styles

private static JsonSerializerOptions jso = new()
private static readonly JsonSerializerOptions jso = new()
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) },
};

#pragma warning restore IDE1006 // Naming Styles

private readonly IEnumerable<IChart> _charts = charts ?? throw new ArgumentNullException(nameof(charts));

/// <inheritdoc />
public async Task RunAsync(string[] args)
{
Expand Down
38 changes: 38 additions & 0 deletions samples/SpotifyPlaylist.ConsoleApp/Configs/AzureSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace SpotifyPlaylist.ConsoleApp.Configs;

/// <summary>
/// This represents the app settings entity for Azure.
/// </summary>
public class AzureSettings
{
/// <summary>
/// Define the name of the settings.
/// </summary>
public const string Name = "Azure";

/// <summary>
/// Gets or sets the <see cref="ApiManagementSettings"/> instance.
/// </summary>
public ApiManagementSettings? APIM { get; set; }
}

/// <summary>
/// This represents the app settings entity for API Management.
/// </summary>
public class ApiManagementSettings
{
/// <summary>
/// Define the name of the settings.
/// </summary>
public const string Name = "APIM";

/// <summary>
/// Gets or sets the base URL.
/// </summary>
public string? BaseUrl { get; set; }

/// <summary>
/// Gets or sets the subscription key.
/// </summary>
public string? SubscriptionKey { get; set; }
}
53 changes: 53 additions & 0 deletions samples/SpotifyPlaylist.ConsoleApp/Configs/SpotifySettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
namespace SpotifyPlaylist.ConsoleApp.Configs;

/// <summary>
/// This represents the app settings entity for Spotify.
/// </summary>
public class SpotifySettings
{
/// <summary>
/// Define the name of the settings.
/// </summary>
public const string Name = "Spotify";

/// <summary>
/// Gets or sets the market. Default is "KR".
/// </summary>
public string? Market { get; set; } = "KR";

/// <summary>
/// Gets or sets the maximum number of items to return. Default is 10.
/// </summary>
public int? MaxItems { get; set; } = 10;

/// <summary>
/// Gets or sets the time zone ID. Default is "Asia/Seoul".
/// </summary>
public string? TimeZoneId { get; set; } = "Asia/Seoul";

/// <summary>
/// Gets or sets the <see cref="SpotifyPlaylistSettings"/> instance.
/// </summary>
public SpotifyPlaylistSettings? Playlist { get; set; }
}

/// <summary>
/// This represents the app settings entity for Spotify playlist.
/// </summary>
public class SpotifyPlaylistSettings
{
/// <summary>
/// Gets or sets the name of the playlist.
/// </summary>
public string? Name { get; set; }

/// <summary>
/// Gets or sets the description of the playlist.
/// </summary>
public string? Description { get; set; }

/// <summary>
/// Gets or sets the cover image URL of the playlist.
/// </summary>
public string? CoverImageUrl { get; set; }
}
90 changes: 90 additions & 0 deletions samples/SpotifyPlaylist.ConsoleApp/Options/ArgumentOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
namespace SpotifyPlaylist.ConsoleApp.Options;

/// <summary>
/// This represents the options entity for arguments.
/// </summary>
public class ArgumentOptions
{
/// <summary>
/// Gets or sets the source that contains the Melon Chart data.
/// </summary>
public string? Source { get; set; }

/// <summary>
/// Gets or sets the source type.
/// </summary>
public SourceType SourceType { get; set; }

/// <summary>
/// Gets or sets the query to search for.
/// </summary>
public string? Query { get; set; }

/// <summary>
/// Gets or sets the value indicating whether to output as JSON or not.
/// </summary>
public bool OutputAsJson { get; set; } = false;

/// <summary>
/// Gets or sets the value indicating whether to display help or not.
/// </summary>
public bool Help { get; set; } = false;

/// <summary>
/// Parses the arguments and returns the <see cref="ArgumentOptions"/> instance.
/// </summary>
/// <param name="args">List of arguments.</param>
/// <returns>Returns the <see cref="ArgumentOptions"/> instance.</returns>
public static ArgumentOptions Parse(string[] args)
{
var options = new ArgumentOptions();
if (args.Length == 0)
{
return options;
}

for (var i = 0; i < args.Length; i++)
{
var arg = args[i];
switch (arg)
{
case "-t":
case "--source-type":
if (i < args.Length - 1)
{
options.SourceType = Enum.TryParse<SourceType>(args[++i], ignoreCase: true, out var result)
? result
: SourceType.Undefined;
}
break;

case "-s":
case "--source":
if (i < args.Length - 1)
{
options.Source = args[++i];
}
break;

case "-q":
case "--query":
if (i < args.Length - 1)
{
options.Query = args[++i];
}
break;

case "--json":
options.OutputAsJson = true;
break;

case "-h":
case "--help":
options.Help = true;
break;
}
}

return options;
}
}
22 changes: 22 additions & 0 deletions samples/SpotifyPlaylist.ConsoleApp/Options/SourceType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace SpotifyPlaylist.ConsoleApp.Options;

/// <summary>
/// This defines the source type enumeration.
/// </summary>
public enum SourceType
{
/// <summary>
/// Identifies undefined source type.
/// </summary>
Undefined,

/// <summary>
/// Identifies Melon Chart.
/// </summary>
Melon,

/// <summary>
/// Identifies Spotify.
/// </summary>
Spotify
}
30 changes: 30 additions & 0 deletions samples/SpotifyPlaylist.ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

using SpotifyPlaylist.ConsoleApp.Configs;
using SpotifyPlaylist.ConsoleApp.Services;

var host = Host.CreateDefaultBuilder(args)
.UseConsoleLifetime()
.ConfigureServices(services =>
{
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.Development.json", optional: true, reloadOnChange: true)
.Build();
var apim = config.GetSection(AzureSettings.Name).GetSection(ApiManagementSettings.Name).Get<ApiManagementSettings>();
var spotify = config.GetSection("Spotify").Get<SpotifySettings>();

services.AddSingleton(spotify!);

services.AddHttpClient<ISpotifyPlaylistService, SpotifyPlaylistService>((services, http) =>
{
http.BaseAddress = new Uri(apim?.BaseUrl!);
http.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", apim?.SubscriptionKey!);
});
})
.Build();

var service = host.Services.GetRequiredService<ISpotifyPlaylistService>();
await service.RunAsync(args);
30 changes: 30 additions & 0 deletions samples/SpotifyPlaylist.ConsoleApp/ProjectPathInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Runtime.CompilerServices;

namespace SpotifyPlaylist.ConsoleApp;

/// <summary>
/// This represents the project path information entity.
/// </summary>
/// <remarks>Reference: https://stackoverflow.com/questions/816566/how-do-you-get-the-current-project-directory-from-c-sharp-code-when-creating-a-c#answer-68864779</remarks>
internal static class ProjectPathInfo
{
public static string CSharpClassFileName = nameof(ProjectPathInfo) + ".cs";
public static string CSharpClassPath;
public static string ProjectPath;

/// <summary>
/// Initializes static members of the <see cref="ProjectPathInfo"/> class.
/// </summary>
static ProjectPathInfo()
{
CSharpClassPath = GetSourceFilePathName();
ProjectPath = Directory.GetParent(CSharpClassPath)!.FullName;
}

/// <summary>
/// Gets the source file path name.
/// </summary>
/// <param name="callerFilePath">File path of the caller.</param>
/// <returns>Returns the file path of the caller.</returns>
private static string GetSourceFilePathName([CallerFilePath] string? callerFilePath = null) => callerFilePath ?? "";
}
12 changes: 12 additions & 0 deletions samples/SpotifyPlaylist.ConsoleApp/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"profiles": {
"Daily100": {
"commandName": "Project",
"commandLineArgs": "-t melon -s ../../data/daily100-20240716.json --json"
},
"Spotify": {
"commandName": "Project",
"commandLineArgs": "-t spotify -s 20R8anptqFQTGk4P2X6dRp --json"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace SpotifyPlaylist.ConsoleApp.Services;

/// <summary>
/// This provides interfaces to the <see cref="SpotifyPlaylistService"/> class.
/// </summary>
public interface ISpotifyPlaylistService
{
/// <summary>
/// Runs the application asynchronously.
/// </summary>
/// <param name="args">List of arguments.</param>
Task RunAsync(string[] args);
}
Loading