Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f98429159f | |||
| 3dca408356 | |||
| 1655e342b7 | |||
| 7223c35658 | |||
| b85bcd1c7a | |||
| 8536d335bc | |||
| b34f7436c2 | |||
| 8b5803c085 | |||
| 5e2a7b53c9 | |||
| d88cfa2cd3 | |||
| cd30876beb |
@@ -2,6 +2,8 @@
|
|||||||
@import "colors";
|
@import "colors";
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
scrollbar-color: $accentColor transparent;
|
||||||
|
scrollbar-width: thin;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
@@ -18,6 +20,7 @@
|
|||||||
.stickyTop {
|
.stickyTop {
|
||||||
top: 0;
|
top: 0;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -34,6 +37,8 @@ body {
|
|||||||
#content {
|
#content {
|
||||||
grid-area: Content;
|
grid-area: Content;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
height: 100dvh;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
/* margin-left: $navBarSize; */
|
/* margin-left: $navBarSize; */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,13 @@ pub fn MediaItem(props: MediaItemProps) -> Element {
|
|||||||
let filename = item.file_name;
|
let filename = item.file_name;
|
||||||
let id = item.id.unwrap().value;
|
let id = item.id.unwrap().value;
|
||||||
let thumb = item.thumb_url;
|
let thumb = item.thumb_url;
|
||||||
|
let url = item.media_url;
|
||||||
return rsx! {
|
return rsx! {
|
||||||
a { class: "mediaItem", href: "{HOST}/m/{id}", target: "_blank",
|
a {
|
||||||
|
class: "mediaItem",
|
||||||
|
href: "{HOST}/{url}",
|
||||||
|
target: "_blank",
|
||||||
|
"data-id" : id,
|
||||||
img { src: "{HOST}{thumb}" }
|
img { src: "{HOST}{thumb}" }
|
||||||
span { class: "info",
|
span { class: "info",
|
||||||
span { class: "name", "{filename}" }
|
span { class: "name", "{filename}" }
|
||||||
|
|||||||
@@ -9,14 +9,14 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="FFMpegCore" Version="5.2.0" />
|
<PackageReference Include="FFMpegCore" Version="5.2.0" />
|
||||||
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0" />
|
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.6" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.7" />
|
||||||
<PackageReference Include="MaybeError" Version="1.1.0" />
|
<PackageReference Include="MaybeError" Version="1.1.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.6" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.7" />
|
||||||
<PackageReference Include="MongoDB.Driver" Version="3.4.0" />
|
<PackageReference Include="MongoDB.Driver" Version="3.4.1" />
|
||||||
<PackageReference Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="2.1.0" />
|
<PackageReference Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="2.1.0" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.6" />
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.6" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.12.1" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.12.1" />
|
||||||
<PackageReference Include="ZLinq" Version="1.4.12" />
|
<PackageReference Include="ZLinq" Version="1.5.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using MongoDB.Bson;
|
using MongoDB.Bson;
|
||||||
using MongoDB.Bson.Serialization.Attributes;
|
using MongoDB.Bson.Serialization.Attributes;
|
||||||
|
|
||||||
|
using SixLabors.ImageSharp;
|
||||||
|
|
||||||
namespace AobaCore.Models;
|
namespace AobaCore.Models;
|
||||||
|
|
||||||
[BsonIgnoreExtraElements]
|
[BsonIgnoreExtraElements]
|
||||||
@@ -16,23 +18,27 @@ public class Media
|
|||||||
public ObjectId Owner { get; set; }
|
public ObjectId Owner { get; set; }
|
||||||
public DateTime UploadDate { get; set; }
|
public DateTime UploadDate { get; set; }
|
||||||
public string[] Tags { get; set; } = [];
|
public string[] Tags { get; set; } = [];
|
||||||
|
public Size? Dimensions { get; set; }
|
||||||
public Dictionary<ThumbnailSize, ObjectId> Thumbnails { get; set; } = [];
|
public Dictionary<ThumbnailSize, ObjectId> Thumbnails { get; set; } = [];
|
||||||
|
|
||||||
|
|
||||||
public static readonly Dictionary<string, MediaType> KnownTypes = new()
|
public static readonly Dictionary<string, MediaType> KnownTypes = new()
|
||||||
{
|
{
|
||||||
{ ".jpg", MediaType.Image },
|
{ ".jpg", MediaType.Image },
|
||||||
{ ".avif", MediaType.Image },
|
|
||||||
{ ".jpeg", MediaType.Image },
|
{ ".jpeg", MediaType.Image },
|
||||||
|
{ ".jxr", MediaType.Image },
|
||||||
|
{ ".avif", MediaType.Image },
|
||||||
{ ".png", MediaType.Image },
|
{ ".png", MediaType.Image },
|
||||||
{ ".apng", MediaType.Image },
|
{ ".apng", MediaType.Image },
|
||||||
{ ".webp", MediaType.Image },
|
{ ".webp", MediaType.Image },
|
||||||
|
{ ".qoi", MediaType.Image },
|
||||||
{ ".ico", MediaType.Image },
|
{ ".ico", MediaType.Image },
|
||||||
{ ".gif", MediaType.Image },
|
{ ".gif", MediaType.Image },
|
||||||
{ ".mp3", MediaType.Audio },
|
{ ".mp3", MediaType.Audio },
|
||||||
{ ".flac", MediaType.Audio },
|
{ ".flac", MediaType.Audio },
|
||||||
{ ".alac", MediaType.Audio },
|
{ ".alac", MediaType.Audio },
|
||||||
{ ".mp4", MediaType.Video },
|
{ ".mp4", MediaType.Video },
|
||||||
|
{ ".m4v", MediaType.Video },
|
||||||
{ ".webm", MediaType.Video },
|
{ ".webm", MediaType.Video },
|
||||||
{ ".mov", MediaType.Video },
|
{ ".mov", MediaType.Video },
|
||||||
{ ".avi", MediaType.Video },
|
{ ".avi", MediaType.Video },
|
||||||
@@ -50,6 +56,10 @@ public class Media
|
|||||||
{ ".xml", MediaType.Code },
|
{ ".xml", MediaType.Code },
|
||||||
{ ".json", MediaType.Code },
|
{ ".json", MediaType.Code },
|
||||||
{ ".py", MediaType.Code },
|
{ ".py", MediaType.Code },
|
||||||
|
{ ".rs", MediaType.Code },
|
||||||
|
{ ".zed", MediaType.Code },
|
||||||
|
{ ".ts", MediaType.Code },
|
||||||
|
{ ".astro", MediaType.Code },
|
||||||
};
|
};
|
||||||
|
|
||||||
[BsonConstructor]
|
[BsonConstructor]
|
||||||
@@ -75,7 +85,7 @@ public class Media
|
|||||||
{
|
{
|
||||||
return this switch
|
return this switch
|
||||||
{
|
{
|
||||||
//Media { MediaType: MediaType.Raw or MediaType.Text or MediaType.Code} => $"/i/dl/{MediaId}/{Filename}",
|
Media { MediaType: MediaType.Raw or MediaType.Text or MediaType.Code } => $"/m/{MediaId}/{Uri.EscapeDataString(Filename)}",
|
||||||
_ => $"/m/{MediaId}"
|
_ => $"/m/{MediaId}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ using AobaCore.Models;
|
|||||||
|
|
||||||
using MaybeError.Errors;
|
using MaybeError.Errors;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
using MongoDB.Bson;
|
using MongoDB.Bson;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
using MongoDB.Driver.GridFS;
|
using MongoDB.Driver.GridFS;
|
||||||
@@ -69,6 +71,7 @@ public class AobaService(IMongoDatabase db)
|
|||||||
{
|
{
|
||||||
var fileId = await _gridFs.UploadFromStreamAsync(filename, data, cancellationToken: cancellationToken);
|
var fileId = await _gridFs.UploadFromStreamAsync(filename, data, cancellationToken: cancellationToken);
|
||||||
var media = new Media(fileId, filename, owner);
|
var media = new Media(fileId, filename, owner);
|
||||||
|
|
||||||
await AddMediaAsync(media, cancellationToken);
|
await AddMediaAsync(media, cancellationToken);
|
||||||
return media;
|
return media;
|
||||||
}
|
}
|
||||||
@@ -76,6 +79,10 @@ public class AobaService(IMongoDatabase db)
|
|||||||
{
|
{
|
||||||
return ex;
|
return ex;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
data.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<MaybeEx<GridFSDownloadStream, GridFSException>> GetFileStreamAsync(ObjectId mediaId, bool seekable = false, CancellationToken cancellationToken = default)
|
public async Task<MaybeEx<GridFSDownloadStream, GridFSException>> GetFileStreamAsync(ObjectId mediaId, bool seekable = false, CancellationToken cancellationToken = default)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
using FFMpegCore;
|
using FFMpegCore;
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
|
|
||||||
|
|
||||||
using MaybeError.Errors;
|
using MaybeError.Errors;
|
||||||
|
|
||||||
using MongoDB.Bson;
|
using MongoDB.Bson;
|
||||||
@@ -10,6 +11,7 @@ using MongoDB.Driver;
|
|||||||
using MongoDB.Driver.GridFS;
|
using MongoDB.Driver.GridFS;
|
||||||
|
|
||||||
using SixLabors.ImageSharp;
|
using SixLabors.ImageSharp;
|
||||||
|
using SixLabors.ImageSharp.Formats;
|
||||||
using SixLabors.ImageSharp.Processing;
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
@@ -24,7 +26,6 @@ namespace AobaCore.Services;
|
|||||||
public class ThumbnailService(IMongoDatabase db, AobaService aobaService)
|
public class ThumbnailService(IMongoDatabase db, AobaService aobaService)
|
||||||
{
|
{
|
||||||
private readonly GridFSBucket _gridfs = new GridFSBucket(db);
|
private readonly GridFSBucket _gridfs = new GridFSBucket(db);
|
||||||
private Lock _lock = new();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -92,17 +93,29 @@ public class ThumbnailService(IMongoDatabase db, AobaService aobaService)
|
|||||||
{
|
{
|
||||||
return type switch
|
return type switch
|
||||||
{
|
{
|
||||||
MediaType.Image => await GenerateImageThumbnailAsync(stream, size, cancellationToken),
|
MediaType.Image => await GenerateImageThumbnailAsync(stream, size, ext, cancellationToken),
|
||||||
MediaType.Video => GenerateVideoThumbnail(stream, size, cancellationToken),
|
MediaType.Video => GenerateVideoThumbnail(stream, size, cancellationToken),
|
||||||
MediaType.Text or MediaType.Code => await GenerateDocumentThumbnailAsync(stream, size, cancellationToken),
|
MediaType.Text or MediaType.Code => await GenerateDocumentThumbnailAsync(stream, size, cancellationToken),
|
||||||
_ => new Error($"No Thumbnail for {type}"),
|
_ => new Error($"No Thumbnail for {type}"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<Stream> GenerateImageThumbnailAsync(Stream stream, ThumbnailSize size, CancellationToken cancellationToken = default)
|
private static Maybe<Image> LoadImage(Stream stream, string ext)
|
||||||
{
|
{
|
||||||
var img = Image.Load(stream);
|
if (ext is ".heif" or ".avif")
|
||||||
img.Mutate(o =>
|
{
|
||||||
|
return new Error("Unsupported image type");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Image.Load(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<Maybe<Stream>> GenerateImageThumbnailAsync(Stream stream, ThumbnailSize size, string ext, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var img = LoadImage(stream, ext);
|
||||||
|
if (img.HasError)
|
||||||
|
return img.Error;
|
||||||
|
img.Value.Mutate(o =>
|
||||||
{
|
{
|
||||||
var size =
|
var size =
|
||||||
o.Resize(new ResizeOptions
|
o.Resize(new ResizeOptions
|
||||||
@@ -113,7 +126,8 @@ public class ThumbnailService(IMongoDatabase db, AobaService aobaService)
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
var result = new MemoryStream();
|
var result = new MemoryStream();
|
||||||
await img.SaveAsWebpAsync(result, cancellationToken);
|
await img.Value.SaveAsWebpAsync(result, cancellationToken);
|
||||||
|
img.Value.Dispose();
|
||||||
result.Position = 0;
|
result.Position = 0;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -121,25 +135,35 @@ public class ThumbnailService(IMongoDatabase db, AobaService aobaService)
|
|||||||
public Maybe<Stream> GenerateVideoThumbnail(Stream data, ThumbnailSize size, CancellationToken cancellationToken = default)
|
public Maybe<Stream> GenerateVideoThumbnail(Stream data, ThumbnailSize size, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var w = (int)size;
|
var w = (int)size;
|
||||||
var source = new MemoryStream();
|
var fn = ObjectId.GenerateNewId().ToString();
|
||||||
|
var filePath = $"/tmp/{fn}.in";
|
||||||
|
using var source = new FileStream(filePath, FileMode.CreateNew);
|
||||||
data.CopyTo(source);
|
data.CopyTo(source);
|
||||||
source.Position = 0;
|
source.Flush();
|
||||||
var output = new MemoryStream();
|
source.Dispose();
|
||||||
FFMpegArguments.FromPipeInput(new StreamPipeSource(source), opt =>
|
data.Dispose();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
opt.WithCustomArgument("-t 5");
|
var output = new MemoryStream();
|
||||||
}).OutputToPipe(new StreamPipeSink(output), opt =>
|
FFMpegArguments.FromFileInput(filePath, false, opt =>
|
||||||
|
{
|
||||||
|
opt.WithCustomArgument("-t 5");
|
||||||
|
}).OutputToPipe(new StreamPipeSink(output), opt =>
|
||||||
|
{
|
||||||
|
opt.WithCustomArgument($"-vf \"crop='min(in_w,in_h)':'min(in_w,in_h)',scale={w}:{w}\" -loop 0 -r 15")
|
||||||
|
.ForceFormat("webp");
|
||||||
|
}).ProcessSynchronously();
|
||||||
|
output.Position = 0;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
opt.WithCustomArgument($"-vf \"crop='min(in_w,in_h)':'min(in_w,in_h)',scale={w}:{w}\" -loop 0 -r 15")
|
return ex;
|
||||||
.ForceFormat("webp");
|
}
|
||||||
}).Configure(cfg =>
|
finally
|
||||||
{
|
{
|
||||||
#if !DEBUG
|
File.Delete(filePath);
|
||||||
cfg.BinaryFolder = "/usr/bin";
|
}
|
||||||
#endif
|
|
||||||
}).ProcessSynchronously();
|
|
||||||
output.Position = 0;
|
|
||||||
return output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Maybe<Stream>> GenerateDocumentThumbnailAsync(Stream data, ThumbnailSize size, CancellationToken cancellationToken = default)
|
public async Task<Maybe<Stream>> GenerateDocumentThumbnailAsync(Stream data, ThumbnailSize size, CancellationToken cancellationToken = default)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0" />
|
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.6" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.7" />
|
||||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.12.1" />
|
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.12.1" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
|
||||||
<PackageReference Include="MimeTypesMap" Version="1.0.9" />
|
<PackageReference Include="MimeTypesMap" Version="1.0.9" />
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.9.0-beta.2" />
|
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.9.0-beta.2" />
|
||||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
|
||||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
|
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.12.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -14,10 +14,11 @@ namespace AobaServer.Controllers;
|
|||||||
public class MediaController(AobaService aobaService, ILogger<MediaController> logger) : Controller
|
public class MediaController(AobaService aobaService, ILogger<MediaController> logger) : Controller
|
||||||
{
|
{
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
|
[HttpGet("{id}/*")]
|
||||||
[ResponseCache(Duration = int.MaxValue)]
|
[ResponseCache(Duration = int.MaxValue)]
|
||||||
public async Task<IActionResult> MediaAsync(ObjectId id, [FromServices] MongoClient client, CancellationToken cancellationToken)
|
public async Task<IActionResult> MediaAsync(ObjectId id, [FromServices] MongoClient client, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var file = await aobaService.GetFileStreamAsync(id, cancellationToken: cancellationToken);
|
var file = await aobaService.GetFileStreamAsync(id, seekable: true, cancellationToken: cancellationToken);
|
||||||
if (file.HasError)
|
if (file.HasError)
|
||||||
{
|
{
|
||||||
logger.LogError(file.Error.Exception, "Failed to load media stream");
|
logger.LogError(file.Error.Exception, "Failed to load media stream");
|
||||||
@@ -58,6 +59,7 @@ public class MediaController(AobaService aobaService, ILogger<MediaController> l
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("/t/{id}")]
|
[HttpGet("/t/{id}")]
|
||||||
|
[ResponseCache(Duration = int.MaxValue)]
|
||||||
public async Task<IActionResult> ThumbAsync(ObjectId id, [FromServices] ThumbnailService thumbnailService, CancellationToken cancellationToken = default)
|
public async Task<IActionResult> ThumbAsync(ObjectId id, [FromServices] ThumbnailService thumbnailService, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var thumb = await thumbnailService.GetThumbnailByFileIdAsync(id, cancellationToken);
|
var thumb = await thumbnailService.GetThumbnailByFileIdAsync(id, cancellationToken);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ RUN dx bundle --platform web
|
|||||||
# Server Build
|
# Server Build
|
||||||
# This stage is used when running from VS in fast mode (Default for Debug configuration)
|
# This stage is used when running from VS in fast mode (Default for Debug configuration)
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
||||||
|
RUN apt-get update && apt-get install -y ffmpeg
|
||||||
USER $APP_UID
|
USER $APP_UID
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
@@ -57,9 +58,8 @@ RUN dotnet publish "./AobaServer.csproj" -c $BUILD_CONFIGURATION -o /app/publish
|
|||||||
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
|
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
|
||||||
FROM base AS final
|
FROM base AS final
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
USER root
|
|
||||||
RUN apt-get update && apt-get install -y ffmpeg
|
|
||||||
COPY --from=publish /app/publish .
|
COPY --from=publish /app/publish .
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
|
|
||||||
ENV APP_VERSION=$VERSION
|
ENV APP_VERSION=$VERSION
|
||||||
ENTRYPOINT ["dotnet", "AobaServer.dll"]
|
ENTRYPOINT ["dotnet", "AobaServer.dll"]
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ message MediaModel {
|
|||||||
int32 viewCount = 5;
|
int32 viewCount = 5;
|
||||||
Id owner = 6;
|
Id owner = 6;
|
||||||
string thumbUrl = 7;
|
string thumbUrl = 7;
|
||||||
|
string mediaUrl = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MediaType {
|
enum MediaType {
|
||||||
@@ -99,3 +100,14 @@ message ShareXResponse {
|
|||||||
string error = 2;
|
string error = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
message SearchQuery {
|
||||||
|
optional string queryText = 1;
|
||||||
|
repeated Filter filters = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Filter {
|
||||||
|
string key = 1;
|
||||||
|
repeated string values = 2;
|
||||||
|
}
|
||||||
@@ -56,6 +56,7 @@ public static class ProtoExtensions
|
|||||||
Owner = media.Owner.ToId(),
|
Owner = media.Owner.ToId(),
|
||||||
ViewCount = media.ViewCount,
|
ViewCount = media.ViewCount,
|
||||||
ThumbUrl = thumbUrl,
|
ThumbUrl = thumbUrl,
|
||||||
|
MediaUrl = media.GetMediaUrl()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user