This repository has been archived by the owner on Oct 25, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgram.cs
151 lines (132 loc) · 5.76 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Serilog;
using YoutubeDLSharp;
using YoutubeDLSharp.Options;
namespace docker_sound_dl
{
class Program
{
private static ILogger logger;
private static BlobContainerClient containerClient;
public static string YtdlPath { get; set; } = "/usr/bin/yt-dlp";
static async Task Main()
{
// 建立Logger
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.Console()
.CreateLogger();
logger = Log.Logger;
// 同步執行
bool sync = null != Environment.GetEnvironmentVariable("SCYNCHRONOUS");
// 計時
DateTime startTime = DateTime.Now;
logger.Information("Start sound-dl {now}", startTime.ToString());
// Create a BlobServiceClient object which will be used to create a container client
string connectionString = Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION_STRING");
BlobServiceClient blobServiceClient = new(connectionString);
containerClient = blobServiceClient.GetBlobContainerClient("sound-buttons");
// 取得要下載的連結
string channelsToDownload = Environment.GetEnvironmentVariable("CHANNELS_IN_ARRAY");
string[] channels = JsonSerializer.Deserialize<string[]>(channelsToDownload);
// TempPath
string tempDir = Path.Combine(Path.GetTempPath(), "audio-dl");
_ = Directory.CreateDirectory(tempDir);
string archivePath = Path.Combine(Path.GetTempPath(), "archive.txt");
try
{
// 取得archive.txt
BlobClient archiveBlob = containerClient.GetBlobClient("AudioSource/archive.txt");
if (archiveBlob.Exists())
{
_ = archiveBlob.DownloadTo(archivePath);
}
OptionSet optionSet = new()
{
Format = "251",
NoCheckCertificate = true,
Output = Path.Combine(tempDir, "%(id)s"),
DownloadArchive = archivePath,
Continue = true,
IgnoreErrors = true,
NoOverwrites = true
};
YoutubeDLProcess ytdlProc = new(YtdlPath);
ytdlProc.OutputReceived += (o, e) => logger.Verbose(e.Data);
ytdlProc.ErrorReceived += (o, e) => logger.Error(e.Data);
logger.Information("Start download process.");
// 下載音訊
await ytdlProc.RunAsync(
channels,
optionSet,
new System.Threading.CancellationToken());
// 上傳blob storage
List<Task> tasks = new();
foreach (string filePath in Directory.GetFiles(tempDir))
{
Task<bool> task = UploadToAzure(filePath);
tasks.Add(task);
if (sync) await task;
}
tasks.Add(UploadToAzure(archivePath, ContentType: "text/plain"));
await Task.WhenAll(tasks.ToArray());
logger.Debug("All tasks are completed. Total time spent: {timeSpent}", (DateTime.Now - startTime).ToString("hh\\:mm\\:ss"));
}
finally
{
Directory.Delete(tempDir, true);
Log.CloseAndFlush();
}
}
/// <summary>
/// 上傳檔案至Azure Blob Storage
/// </summary>
/// <param name="containerClient"></param>
/// <param name="tempDir">用來計算Storage內路徑的基準路徑</param>
/// <param name="filePath">上傳檔案路徑</param>
/// <returns></returns>
private static async Task<bool> UploadToAzure(string filePath, bool retry = true, string ContentType = "audio/webm")
{
bool isVideo = ContentType == "audio/webm";
try
{
using FileStream fs = new(filePath, FileMode.Open, FileAccess.Read);
logger.Debug("Start Upload {path} to azure storage", filePath);
long fileSize = new FileInfo(filePath).Length;
// 覆寫
_ = await containerClient
.GetBlobClient($"AudioSource/{Path.GetFileName(filePath)}")
.UploadAsync(content: fs,
httpHeaders: new BlobHttpHeaders { ContentType = ContentType },
accessTier: AccessTier.Hot,
progressHandler: new Progress<long>(progress =>
{
logger.Verbose("Uploading...{progress}% {path}", Math.Round(((double)progress) / fileSize * 100), filePath);
}));
logger.Debug("Finish Upload {path} to azure storage", filePath);
if (isVideo) File.Delete(filePath);
return true;
}
catch (Exception e)
{
if (retry)
{
// Retry Once
return await UploadToAzure(filePath, false);
}
else
{
logger.Error("Upload Failed: {fileName}", Path.GetFileName(filePath));
logger.Error("{errorMessage}", e.Message);
return false;
}
}
}
}
}