Dateiexport zu YouTube in .NET C# mit Open-Source-Bibliotheken
Laden Sie mit Googles Open-Source-.NET-Client eine lokale MP4 auf Ihren YouTube-Kanal hoch. Diese Konsolen-App fordert ausschließlich Upload-Zugriff an, setzt das Video auf privat, deaktiviert Benachrichtigungen für Abonnenten und gibt die von YouTube zurückgegebene Video-ID aus. Die Annahme des Uploads und die abgeschlossene Videoverarbeitung sind separate Ergebnisse.
Voraussetzungen
Diese Anleitung verwendet Bash unter Linux und einen Browser auf demselben Computer. Installieren Sie das .NET 10 SDK mit einem aktuellen Sicherheitspatch. Das lokale Beispiel wurde mit SDK 10.0.403 und Runtime 10.0.14 geprüft. Das SDK enthält die Runtime; die Runtime allein kann kein Projekt erstellen oder bauen.
Sie benötigen außerdem eine kleine, abspielbare MP4, die Ihnen gehört oder die Sie hochladen dürfen,
einen YouTube-Kanal und dessen Kanal-ID. Folgen Sie der
Anleitung zur Kanal-ID von YouTube, während Sie als primärer
Inhaber des gewünschten Kanals angemeldet sind. Verwenden Sie UTF-8-Dateinamen. Diese App sendet
die Datei als video/mp4; sie wandelt andere Dateien nicht in Videos um
und validiert ihre Codecs nicht.
Folgen Sie Googles Projekt- und OAuth-Einrichtung, um die YouTube Data API v3 in einem Google-Cloud-Projekt zu aktivieren. Konfigurieren Sie den Zustimmungsbildschirm und fügen Sie Ihr Google-Konto als Testnutzer hinzu, wenn sich die App im Testmodus befindet. Erstellen Sie einen OAuth-Client vom Typ Desktop app und laden Sie dessen JSON-Datei an einen privaten Speicherort außerhalb Ihres Quellcode-Repositorys herunter. Ein API-Schlüssel autorisiert keine Uploads.
Googles Desktop-OAuth-Flow verwendet einen Browser und einen lokalen Callback-Listener. Dieses Beispiel ist für eine interaktive lokale Anwendung gedacht; ein entfernter Headless-Server benötigt ein separates Autorisierungskonzept. Wählen Sie bei der Zustimmung den gewünschten YouTube-Kanal aus, gegebenenfalls einschließlich des Brand-Kontos. Ein Google-Konto kann mehr als einen Kanal haben.
YouTube-API-Client einrichten
Beginnen Sie in einem beschreibbaren Ordner außerhalb eines bestehenden .NET-Projekts.
Die folgende Schutzprüfung lehnt übergeordnete Projektkonfigurationen ab, damit eine geerbte
SDK-Festlegung oder Build-Einstellungen dieses eigenständige Beispiel nicht unbemerkt verändern.
Sie erstellt einen neuen Ordner namens youtube-upload und belässt Ihre Shell
im ursprünglichen Verzeichnis. Ein vorhandener Ordner bleibt erhalten und stoppt die Einrichtung.
(
command -v dotnet >/dev/null || exit 1
parent=$(pwd -P)
while :; do
for name in global.json Directory.Build.props Directory.Build.targets Directory.Packages.props NuGet.Config nuget.config NuGet.config; do
if [ -e "$parent/$name" ]; then
printf 'Use a folder without parent .NET configuration: %s\n' "$parent/$name" >&2
exit 1
fi
done
[ "$parent" = / ] && break
parent=${parent%/*}
parent=${parent:-/}
done
dotnet --version &&
mkdir youtube-upload &&
cd youtube-upload &&
dotnet new console --framework net10.0 &&
dotnet add package Google.Apis.YouTube.v3 --version 1.78.0.4309 &&
dotnet build
)
Das Paket ist Googles YouTube Data API-Client für .NET. Wenn Erstellung, Installation oder Build fehlschlagen, beheben Sie den gemeldeten Fehler, bevor Sie fortfahren. Behalten Sie bereits erstellte Dateien bei; fügen Sie den Erstellungsblock nicht über einem bestehenden Projekt ein.
Videos hochladen
Ersetzen Sie die generierte Datei youtube-upload/Program.cs durch dieses vollständige
Programm. Es verwendet GoogleWebAuthorizationBroker und FileDataStore,
um die Benutzerautorisierung einzuholen und zu speichern. Ein Token-Verzeichnis ist dem Kanal
zugeordnet, den Sie bei der Zustimmung ausgewählt haben; sein Name wählt keinen Kanal aus.
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Services;
using Google.Apis.Upload;
using Google.Apis.Util.Store;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;
public static class Program
{
public static async Task<int> Main(string[] args)
{
if (args.Length != 5 || string.IsNullOrWhiteSpace(args[3]) ||
string.IsNullOrWhiteSpace(args[4]) || args[4].Length > 100)
{
Console.Error.WriteLine(
"Usage: client.json video.mp4 token-directory expected-channel-id title");
return 2;
}
if (!File.Exists(args[0]) || !File.Exists(args[1]))
{
Console.Error.WriteLine("OAuth client file or video is missing. No upload started.");
return 2;
}
try
{
using var clientFile = File.OpenRead(args[0]);
using var videoFile = File.OpenRead(args[1]);
using var deadline = new CancellationTokenSource(TimeSpan.FromMinutes(10));
var store = new FileDataStore(Path.GetFullPath(args[2]), true);
var cached = await store.GetAsync<TokenResponse>("channel-owner");
Console.Error.WriteLine(cached is null
? "Opening browser authorization. Select the intended YouTube channel."
: "Using saved authorization; no new channel selection was requested.");
var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.FromStream(clientFile).Secrets,
new[] { YouTubeService.Scope.YoutubeUpload },
"channel-owner", deadline.Token, store);
var scopes = credential.Token.Scope?.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (scopes is null || scopes.Length != 1 ||
scopes[0] != YouTubeService.Scope.YoutubeUpload)
{
Console.Error.WriteLine("Expected upload-only consent. Use a fresh token directory.");
return 1;
}
using var youtube = new YouTubeService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "PrivateVideoUpload"
});
youtube.HttpClient.Timeout = TimeSpan.FromSeconds(60);
await UploadPrivateVideoAsync(youtube, videoFile, args[3], args[4], deadline.Token);
Console.WriteLine("Private upload accepted; processing may still be pending.");
return 0;
}
catch (Exception)
{
Console.Error.WriteLine(
"Upload failed or its outcome is unknown. Inspect the selected channel in " +
"YouTube Studio before retrying. Do not automatically repeat this upload.");
return 1;
}
}
public static async Task<string> UploadPrivateVideoAsync(
YouTubeService youtube, Stream source, string expectedChannelId,
string title, CancellationToken cancellationToken)
{
var video = new Video
{
Snippet = new VideoSnippet { Title = title, CategoryId = "22" },
Status = new VideoStatus { PrivacyStatus = "private" }
};
var upload = youtube.Videos.Insert(video, "snippet,status", source, "video/mp4");
upload.NotifySubscribers = false;
Console.Error.WriteLine($"Upload settings: privacy={video.Status.PrivacyStatus}; notifySubscribers={upload.NotifySubscribers}");
upload.ChunkSize = ResumableUpload.MinimumChunkSize;
upload.ProgressChanged += progress =>
{
if (progress.Status == UploadStatus.Uploading)
Console.Error.WriteLine($"Bytes sent: {progress.BytesSent}");
};
var progress = await upload.UploadAsync(cancellationToken);
progress.ThrowOnFailure();
var result = upload.ResponseBody;
if (progress.Status != UploadStatus.Completed || string.IsNullOrWhiteSpace(result?.Id))
throw new InvalidOperationException("No confirmed video ID was returned.");
Console.WriteLine($"Video ID: {result.Id}");
if (result.Snippet?.ChannelId != expectedChannelId || result.Snippet?.Title != title ||
result.Status?.PrivacyStatus != "private")
throw new InvalidOperationException("Returned video metadata did not match the upload.");
return result.Id;
}
}
Führen Sie im ursprünglichen Arbeitsordner den folgenden Befehl aus, nachdem Sie alle fünf
Argumente ersetzt haben. Wählen Sie für die erste Autorisierung einen ungenutzten privaten Pfad
für das Token-Verzeichnis. Der Befehl baut das gespeicherte Programm, bevor er es ausführt;
-- trennt Anwendungsargumente von .NET-Optionen.
dotnet run --project ./youtube-upload -- \
"/absolute/path/client.json" "/absolute/path/my video.mp4" \
"/absolute/private/path/youtube-channel-tokens" \
"YOUR_CHANNEL_ID" "My private upload"
Schließen Sie Googles Zustimmungsablauf im Browser ab. Das Programm fordert nur
youtube.upload an, einen der von
videos.insert akzeptierten Scopes.
Es sendet explizit privacyStatus=private und notifySubscribers=false,
dessen Standardwert andernfalls true wäre.
Bei Annahme gibt das Programm Video ID: gefolgt von der tatsächlichen ID aus. Speichern Sie diese ID und prüfen Sie das Video in YouTube Studio unter dem ausgewählten Kanal. Das Argument für die erwartete Kanal-ID dient zur Prüfung der zurückgegebenen Metadaten nach dem Upload, nicht zur Auswahl des Ziels oder dazu, einen Upload auf einen falsch autorisierten Kanal zu verhindern. Schlägt die Prüfung fehl, beendet sich das Programm mit einem Fehler, gibt aber die zurückgegebene ID aus, damit Sie das Video finden.
Gesendete Bytes zeigen den Transportfortschritt an. Selbst ein abgeschlossener Upload mit einer
ID beweist nicht, dass YouTube die Verarbeitung zu einem abspielbaren Video abgeschlossen hat.
Prüfen Sie die Verarbeitung vor der Veröffentlichung in YouTube Studio; Google dokumentiert für
diese Phase einen separaten processingDetails.processingStatus.
Kontingente und Ratenlimits handhaben
Prüfen Sie die aktuellen Limits Ihres Projekts in Google Cloud und im
YouTube-Kontingentrechner, bevor Sie Uploads automatisieren.
Am 5. November 2026 ist als Standard ein separates Kontingent von 100 Aufrufen von
videos.insert pro Tag dokumentiert, ergänzt um separate Limits für die Suche
und andere Endpunkte. Tageskontingente werden um Mitternacht Pacific Time zurückgesetzt.
Auch ungültige Anfragen verbrauchen Kontingent.
Ein lokaler Zähler kann andere Prozesse, Neustarts oder sämtliche SDK-Anfragen nicht berücksichtigen. Dieses Beispiel führt einen einzelnen Einfügeversuch auf Anwendungsebene aus; es implementiert keinen projektweiten Kontingent-Scheduler.
Fehler vor einem erneuten Versuch behandeln
Ein Exit-Code ungleich null kann eine Ablehnung, einen Abbruch, ein Timeout oder eine Antwort bedeuten, die verloren ging, nachdem YouTube das Video angenommen hatte. Die App fordert nach zehn Minuten den Abbruch von Autorisierung und Upload an und konfiguriert pro Upload-Anfrage ein HTTP-Timeout von 60 Sekunden. Der Abbruch erfolgt kooperativ und garantiert keine Prozessbeendigung. Eine langsame Verbindung kann einen ansonsten gültigen Upload unterbrechen. Keines der beiden Timeouts beweist, dass ein entfernter Schreibvorgang rückgängig gemacht wurde.
Das SDK verwendet fortsetzbare Upload-Anfragen, doch dieses Programm speichert deren Sitzungs-URI
nicht zur Wiederherstellung nach Prozessende. Umschließen Sie nicht den gesamten Befehl
dotnet run mit einer Wiederholungsschleife: Ein neuer Aufruf von
videos.insert kann ein zweites Video erstellen, wenn die erste Antwort verloren
ging. Prüfen Sie den vorgesehenen Kanal und jede ausgegebene Video-ID, bevor Sie über einen erneuten
Versuch entscheiden. Die Fortschrittsausgabe allein kann ein unbekanntes Ergebnis nicht klären.
Autorisierung an ihren Kanal binden
FileDataStore speichert Tokens dauerhaft; es ist kein verschlüsselter Tresor
für Zugangsdaten. Beschränken Sie den Zugriff auf die Client-JSON-Datei und das Token-Verzeichnis
und halten Sie beide aus der Versionsverwaltung heraus. Bei Wiederverwendung des Verzeichnisses
kann der Browser übersprungen werden. Ein erfolgreicher Lauf mit zwischengespeicherten Daten
belegt daher keine erneute Kanalauswahl. Um einen anderen Kanal zu autorisieren, wählen Sie einen
anderen ungenutzten privaten Pfad für das Token-Verzeichnis und durchlaufen Sie die Zustimmung erneut.
Sie haben jetzt einen Konsolen-Einstiegspunkt für einen einzelnen Upload, dessen bestätigtes Ergebnis die ID eines privaten Videos ist. Lassen Sie das Video privat, bis Sie seinen Kanal, seinen Inhalt und das Verarbeitungsergebnis in YouTube Studio geprüft haben. Informationen zu Anfragefeldern über dieses Beispiel hinaus finden Sie in der offiziellen Upload-Referenz.
