Primeiro commit do projeto VS 2022

This commit is contained in:
Ricardo Carneiro 2025-01-26 18:20:38 -03:00
commit ea0d290deb
17 changed files with 385 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.vs/
bin/
obj/

25
YTExtractor.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35327.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YTExtractor", "YTExtractor\YTExtractor.csproj", "{7DA7D783-153F-42EF-87E4-239DEC80F91A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7DA7D783-153F-42EF-87E4-239DEC80F91A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7DA7D783-153F-42EF-87E4-239DEC80F91A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7DA7D783-153F-42EF-87E4-239DEC80F91A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7DA7D783-153F-42EF-87E4-239DEC80F91A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0A995D46-30D9-42A9-BA92-225340DFC214}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,47 @@
using MongoDB.Driver;
namespace YTExtractor.Data
{
public class MongoDBConnector
{
private readonly IMongoDatabase _database;
private readonly IMongoCollection<VideoData> _collection;
public MongoDBConnector(IConfiguration configuration)
{
var connectionString = configuration.GetSection("MongoDbConnaction").Value;
var client = new MongoClient(connectionString);
_database = client.GetDatabase("YTExtractor");
_collection = _database.GetCollection<VideoData>("videos");
}
public async Task InsertVideo(VideoData video)
{
await _collection.InsertOneAsync(video);
}
public async Task<VideoData> GetVideoById(string id)
{
return await _collection.Find(x => x.Id == id).FirstOrDefaultAsync();
}
public async Task<List<VideoData>> GetAllVideos()
{
return await _collection.Find(_ => true).ToListAsync();
}
public async Task UpdateVideo(VideoData video)
{
await _collection.ReplaceOneAsync(x => x.Id == video.Id, video);
}
public async Task DeleteVideo(string id)
{
await _collection.DeleteOneAsync(x => x.Id == id);
}
public async Task<VideoData> GetVideoByUrl(string url)
{
return await _collection.Find(x => x.Url == url).FirstOrDefaultAsync();
}
}
}

View File

@ -0,0 +1,17 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace YTExtractor.Data
{
public class VideoData
{
[BsonId]
[BsonRepresentation(BsonType.String)]
public string Id { get; set; }
public string Titulo { get; set; }
public string Url { get; set; }
public string ThumbnailUrl { get; set; }
public string TranscText { get; set; }
}
}

19
YTExtractor/Dockerfile Normal file
View File

@ -0,0 +1,19 @@
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet restore
RUN dotnet publish -c Release -o /app
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app .
RUN apt-get update && \
apt-get install -y python3-pip && \
pip3 install yt-dlp && \
mkdir /app/temp && \
chmod 777 /app/temp && \
which yt-dlp || (echo "yt-dlp not found" && exit 1)
EXPOSE 80
ENTRYPOINT ["dotnet", "YTExtractor.dll"]

87
YTExtractor/Program.cs Normal file
View File

@ -0,0 +1,87 @@
using YTExtractor;
using Serilog;
using Serilog.Sinks.InfluxDB;
using YTExtractor.Data;
// App configuration and endpoints
var builder = WebApplication.CreateBuilder(args);
var environment = builder.Environment.EnvironmentName;
Log.Logger = new LoggerConfiguration()
.WriteTo.InfluxDB(
address: "http://192.168.0.76",
dbName: "telegraf",
source: "YTExtractor-{environment}")
.Enrich.WithProperty("Environment", environment)
.CreateLogger();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<MongoDBConnector>();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.MapPost("/api/video-info", async (VideoRequest request, MongoDBConnector mongo) =>
{
try
{
if (!YoutubeService.IsValidYouTubeUrl(request.Url))
return Results.BadRequest("Invalid YouTube URL");
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempDir);
try
{
Log.Information($"Obtendo dados do video: {request.Url}");
var videoExists = await mongo.GetVideoByUrl(request.Url);
if (videoExists != null)
{
return Results.Ok(new VideoInfo(
videoExists.Url,
videoExists.Titulo,
videoExists.ThumbnailUrl,
videoExists.TranscText
));
}
var info = await YoutubeService.GetVideoInfo(request.Url, tempDir);
var subtitles = await YoutubeService.GetSubtitles(request.Url, request.Language, tempDir);
await mongo.InsertVideo(new VideoData
{
Url = request.Url,
Titulo = info.Title,
ThumbnailUrl = info.ThumbnailUrl,
TranscText = subtitles
});
Log.Information($"Dados de video obtidos: {request.Url}");
return Results.Ok(new VideoInfo(
request.Url,
info.Title,
info.ThumbnailUrl,
subtitles
));
}
finally
{
if (Directory.Exists(tempDir))
Directory.Delete(tempDir, true);
}
}
catch (Exception ex)
{
Log.Error(ex, "Failed to get video info");
return Results.Problem(ex.Message);
}
})
.WithName("GetVideoInfo")
.WithOpenApi();
app.Run();

View File

@ -0,0 +1,41 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:49221",
"sslPort": 0
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5102",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7082;http://localhost:5102",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

6
YTExtractor/VideoInfo.cs Normal file
View File

@ -0,0 +1,6 @@
using System;
namespace YTExtractor
{
public record VideoInfo(string Url, string Title, string ThumbnailUrl, string Subtitles);
}

View File

@ -0,0 +1,4 @@
namespace YTExtractor
{
public record VideoRequest(string Url, string Language);
}

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.12" />
<PackageReference Include="MongoDB.Bson" Version="3.1.0" />
<PackageReference Include="MongoDB.Driver" Version="3.1.0" />
<PackageReference Include="Serilog" Version="4.2.1-dev-02337" />
<PackageReference Include="Serilog.Sinks.InfluxDB.DotNetCore" Version="1.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>
<ItemGroup>
<None Update="yt-dlp.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugProfile>https</ActiveDebugProfile>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,6 @@
@YTExtractor_HostAddress = http://localhost:5102
GET {{YTExtractor_HostAddress}}/weatherforecast/
Accept: application/json
###

View File

@ -0,0 +1,76 @@
using Microsoft.Extensions.Hosting.Internal;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace YTExtractor
{
public class YoutubeService
{
public static bool IsValidYouTubeUrl(string urlx)
{
return Regex.IsMatch(urlx, @"^(https?\:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+$");
}
public static async Task<YtDlpInfo> GetVideoInfo(string url, string workingDir)
{
var startInfo = new ProcessStartInfo
{
FileName = "yt-dlp",
Arguments = $"--dump-json {url}",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
WorkingDirectory = workingDir
};
using var process = Process.Start(startInfo);
var output = await process.StandardOutput.ReadToEndAsync();
await process.WaitForExitAsync();
if (process.ExitCode != 0)
throw new Exception("Failed to get video info");
var jsonDoc = JsonDocument.Parse(output);
var root = jsonDoc.RootElement;
return new YtDlpInfo(
root.GetProperty("title").GetString() ?? "",
root.GetProperty("thumbnail").GetString() ?? ""
);
}
public static async Task<string> GetSubtitles(string url, string language, string workingDir)
{
var pathExe = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var exePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? Path.Combine(pathExe, "yt-dlp.exe")
: "yt-dlp";
//var wokingExe = Path.Combine(pathExe, "yt-dlp.exe");
var startInfo = new ProcessStartInfo
{
FileName = exePath,
Arguments = $"--write-sub --write-auto-sub --sub-lang {language} --skip-download {url}",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
WorkingDirectory = workingDir
};
using var process = Process.Start(startInfo);
var output = await process.StandardOutput.ReadToEndAsync();
var error = await process.StandardError.ReadToEndAsync();
await process.WaitForExitAsync();
var subtitleFile = Directory.GetFiles(workingDir, "*.vtt").FirstOrDefault();
if (subtitleFile == null)
throw new Exception("No subtitles found");
return await File.ReadAllTextAsync(subtitleFile);
}
}
}

6
YTExtractor/YtDlpInfo.cs Normal file
View File

@ -0,0 +1,6 @@
using System;
namespace YTExtractor
{
public record YtDlpInfo(string Title, string ThumbnailUrl);
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"MongoDbConnaction": "mongodb://admin:c4rn31r0@192.168.0.82:27017,192.168.0.81:27017/?replicaSet=rs0"
}

BIN
YTExtractor/yt-dlp.exe Normal file

Binary file not shown.