Compare commits
No commits in common. "dd7dd54ca29441544560ead8ee73b3b4e84dd375" and "242b4596ff637e6d5f1a7fcbd730f20303102836" have entirely different histories.
dd7dd54ca2
...
242b4596ff
25
YTExtractor.sln
Normal file
25
YTExtractor.sln
Normal 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
|
||||
47
YTExtractor/Data/MongoDbConnector.cs
Normal file
47
YTExtractor/Data/MongoDbConnector.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
17
YTExtractor/Data/VideoData.cs
Normal file
17
YTExtractor/Data/VideoData.cs
Normal 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
19
YTExtractor/Dockerfile
Normal 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
87
YTExtractor/Program.cs
Normal 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();
|
||||
41
YTExtractor/Properties/launchSettings.json
Normal file
41
YTExtractor/Properties/launchSettings.json
Normal 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
6
YTExtractor/VideoInfo.cs
Normal file
@ -0,0 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace YTExtractor
|
||||
{
|
||||
public record VideoInfo(string Url, string Title, string ThumbnailUrl, string Subtitles);
|
||||
}
|
||||
4
YTExtractor/VideoRequest.cs
Normal file
4
YTExtractor/VideoRequest.cs
Normal file
@ -0,0 +1,4 @@
|
||||
namespace YTExtractor
|
||||
{
|
||||
public record VideoRequest(string Url, string Language);
|
||||
}
|
||||
24
YTExtractor/YTExtractor.csproj
Normal file
24
YTExtractor/YTExtractor.csproj
Normal 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>
|
||||
6
YTExtractor/YTExtractor.csproj.user
Normal file
6
YTExtractor/YTExtractor.csproj.user
Normal 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>
|
||||
6
YTExtractor/YTExtractor.http
Normal file
6
YTExtractor/YTExtractor.http
Normal file
@ -0,0 +1,6 @@
|
||||
@YTExtractor_HostAddress = http://localhost:5102
|
||||
|
||||
GET {{YTExtractor_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
76
YTExtractor/YoutubeService.cs
Normal file
76
YTExtractor/YoutubeService.cs
Normal 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
6
YTExtractor/YtDlpInfo.cs
Normal file
@ -0,0 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace YTExtractor
|
||||
{
|
||||
public record YtDlpInfo(string Title, string ThumbnailUrl);
|
||||
}
|
||||
8
YTExtractor/appsettings.Development.json
Normal file
8
YTExtractor/appsettings.Development.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
10
YTExtractor/appsettings.json
Normal file
10
YTExtractor/appsettings.json
Normal 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
BIN
YTExtractor/yt-dlp.exe
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user