pleroma: media
This commit is contained in:
parent
5e0feab2b3
commit
4a6d5dbb93
4 changed files with 177 additions and 9 deletions
18
Pleroma/CommonMIMEs.cs
Normal file
18
Pleroma/CommonMIMEs.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
namespace Uwaa.Pleroma;
|
||||
|
||||
public enum CommonMIMEs
|
||||
{
|
||||
PNG,
|
||||
JPEG,
|
||||
GIF,
|
||||
|
||||
MP4,
|
||||
WEBM,
|
||||
MOV,
|
||||
|
||||
WAV,
|
||||
MP3,
|
||||
OGG,
|
||||
|
||||
Text,
|
||||
}
|
|
@ -49,6 +49,16 @@ public class Attachment
|
|||
/// </summary>
|
||||
[JsonPropertyName("url")]
|
||||
public string URL { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Downloads the attachment.
|
||||
/// </summary>
|
||||
public async Task<byte[]> Download()
|
||||
{
|
||||
using HttpClient client = new HttpClient();
|
||||
HttpResponseMessage res = await client.GetAsync(URL);
|
||||
return await res.Content.ReadAsByteArrayAsync();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(EnumLowerCaseConverter<AttachmentType>))]
|
||||
|
@ -76,4 +86,31 @@ public class PleromaAttachmentData
|
|||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = null!;
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(MediaIDConverter))]
|
||||
public readonly struct MediaID(string id)
|
||||
{
|
||||
public static implicit operator MediaID(string id) => new MediaID(id);
|
||||
|
||||
public static implicit operator MediaID(Attachment attachment) => new MediaID(attachment.ID);
|
||||
|
||||
public readonly string ID = id;
|
||||
|
||||
public override string ToString() => ID;
|
||||
}
|
||||
|
||||
class MediaIDConverter : JsonConverter<MediaID>
|
||||
{
|
||||
public override bool CanConvert(Type type) => type.IsAssignableTo(typeof(MediaID));
|
||||
|
||||
public override MediaID Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
return new MediaID(reader.GetString() ?? throw new NullReferenceException("Expected a string, got null"));
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, MediaID value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ID);
|
||||
}
|
||||
}
|
|
@ -7,5 +7,25 @@ public class PleromaException : Exception
|
|||
|
||||
public override string Message => Text;
|
||||
|
||||
public override string ToString() => Text;
|
||||
public override string ToString() => Message;
|
||||
}
|
||||
|
||||
public class PleromaAggregateException : Exception
|
||||
{
|
||||
[JsonPropertyName("errors")]
|
||||
public PleromaInnerException[] Text { get; set; } = null!;
|
||||
|
||||
public override string Message => string.Join("\n", (object?[])Text);
|
||||
|
||||
public override string ToString() => Message;
|
||||
}
|
||||
|
||||
public class PleromaInnerException : Exception
|
||||
{
|
||||
[JsonPropertyName("detail")]
|
||||
public string Text { get; set; } = null!;
|
||||
|
||||
public override string Message => Text;
|
||||
|
||||
public override string ToString() => Message;
|
||||
}
|
|
@ -65,7 +65,7 @@ public class Pleroma
|
|||
|
||||
string text = await res.Content.ReadAsStringAsync();
|
||||
|
||||
if (res.StatusCode is >= (HttpStatusCode)400 and < (HttpStatusCode)600)
|
||||
if (res.StatusCode is >= (HttpStatusCode)300)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -87,6 +87,17 @@ public class Pleroma
|
|||
{
|
||||
//Not an error
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
PleromaAggregateException? err = JsonSerializer.Deserialize<PleromaAggregateException>(text, SerializerOptions);
|
||||
if (err != null && err.Text != null)
|
||||
throw err;
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
//Not an error
|
||||
}
|
||||
}
|
||||
|
||||
if (res.StatusCode is >= (HttpStatusCode)200 and < (HttpStatusCode)300)
|
||||
|
@ -179,28 +190,36 @@ public class Pleroma
|
|||
/// <param name="replyTo">ID of the status being replied to, if status is a reply</param>
|
||||
/// <param name="quoting"> ID of the status being quoted.</param>
|
||||
/// <param name="language">ISO 639 language code for this status.</param>
|
||||
/// <param name="attachments">Array of Attachment ids to be attached as media.</param>
|
||||
/// <param name="visibility">Visibility of the posted status.</param>
|
||||
/// <exception cref="HttpRequestException">Thrown if something goes wrong while uploading the status.</exception>
|
||||
/// <returns>The status if posting was successful.</returns>
|
||||
public Task<Status> PostStatus(string content,
|
||||
/// <exception cref="HttpRequestException">Thrown if something goes wrong while publishing the status.</exception>
|
||||
/// <returns>The newly published status if posting was successful.</returns>
|
||||
public Task<Status> PostStatus(string? content = null,
|
||||
bool sensitive = false,
|
||||
int? expiresIn = null,
|
||||
string? replyTo = null,
|
||||
string? quoting = null,
|
||||
string? language = null,
|
||||
MediaID[]? attachments = null,
|
||||
StatusVisibility visibility = StatusVisibility.Public)
|
||||
{
|
||||
if (content == null && (attachments == null || attachments.Length == 0))
|
||||
throw new ArgumentException("Cannot post nothing. Content and/or attachments must be provided.");
|
||||
|
||||
MemoryStream mem = new MemoryStream();
|
||||
|
||||
{
|
||||
Utf8JsonWriter writer = new Utf8JsonWriter(mem, new JsonWriterOptions() { SkipValidation = true });
|
||||
writer.WriteStartObject();
|
||||
|
||||
writer.WritePropertyName("status");
|
||||
writer.WriteStringValue(content);
|
||||
if (content != null)
|
||||
{
|
||||
writer.WritePropertyName("status");
|
||||
writer.WriteStringValue(content);
|
||||
|
||||
writer.WritePropertyName("content-type");
|
||||
writer.WriteStringValue("text/plain");
|
||||
writer.WritePropertyName("content-type");
|
||||
writer.WriteStringValue("text/plain");
|
||||
}
|
||||
|
||||
if (sensitive)
|
||||
{
|
||||
|
@ -232,6 +251,15 @@ public class Pleroma
|
|||
writer.WriteStringValue(language);
|
||||
}
|
||||
|
||||
if (attachments != null)
|
||||
{
|
||||
writer.WritePropertyName("media_ids");
|
||||
writer.WriteStartArray();
|
||||
foreach (MediaID media in attachments)
|
||||
writer.WriteStringValue(media.ID);
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
|
||||
if (visibility != StatusVisibility.Public)
|
||||
{
|
||||
writer.WritePropertyName("visibility");
|
||||
|
@ -250,6 +278,71 @@ public class Pleroma
|
|||
return Retry<Status>(req)!;
|
||||
}
|
||||
|
||||
static string CommonMIMEString(CommonMIMEs mime) => mime switch
|
||||
{
|
||||
CommonMIMEs.PNG => "image/png",
|
||||
CommonMIMEs.JPEG => "image/jpeg",
|
||||
CommonMIMEs.GIF => "image/gif",
|
||||
CommonMIMEs.MP4 => "video/mp4",
|
||||
CommonMIMEs.WEBM => "video/webm",
|
||||
CommonMIMEs.MOV => "video/quicktime",
|
||||
CommonMIMEs.WAV => "audio/vnd.wav",
|
||||
CommonMIMEs.MP3 => "audio/mpeg",
|
||||
CommonMIMEs.OGG => "audio/ogg",
|
||||
CommonMIMEs.Text => "text/plain",
|
||||
_ => throw new ArgumentException("Unknown common MIME", nameof(mime)),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Uploads a file to the server. The resulting attachment can then be included in a status as an attachment.
|
||||
/// </summary>
|
||||
/// <param name="mime">The MIME type of the file.</param>
|
||||
/// <param name="file">An array containing the file's contents.</param>
|
||||
/// <returns>A handle of the uploaded file, including its ID and URLs.</returns>
|
||||
public Task<Attachment> Upload(CommonMIMEs mime, byte[] file) => Upload(CommonMIMEString(mime), file);
|
||||
|
||||
/// <summary>
|
||||
/// Uploads a file to the server. The resulting attachment can then be included in a status as an attachment.
|
||||
/// </summary>
|
||||
/// <param name="mime">The MIME type of the file.</param>
|
||||
/// <param name="file">An array containing the file's contents.</param>
|
||||
/// <returns>A handle of the uploaded file, including its ID and URLs.</returns>
|
||||
public Task<Attachment> Upload(string mime, byte[] file) => Upload(mime, new ByteArrayContent(file));
|
||||
|
||||
/// <summary>
|
||||
/// Uploads a file to the server. The resulting attachment can then be included in a status as an attachment.
|
||||
/// </summary>
|
||||
/// <param name="mime">The MIME type of the file.</param>
|
||||
/// <param name="stream">A stream of the file's contents.</param>
|
||||
/// <returns>A handle of the uploaded file, including its ID and URLs.</returns>
|
||||
public Task<Attachment> Upload(CommonMIMEs mime, Stream stream) => Upload(CommonMIMEString(mime), stream);
|
||||
|
||||
/// <summary>
|
||||
/// Uploads a file to the server. The resulting attachment can then be included in a status as an attachment.
|
||||
/// </summary>
|
||||
/// <param name="mime">The MIME type of the file.</param>
|
||||
/// <param name="stream">A stream of the file's contents.</param>
|
||||
/// <returns>A handle of the uploaded file, including its ID and URLs.</returns>
|
||||
public Task<Attachment> Upload(string mime, Stream stream) => Upload(mime, new StreamContent(stream));
|
||||
|
||||
async Task<Attachment> Upload(string mime, HttpContent content)
|
||||
{
|
||||
content.Headers.ContentType = new MediaTypeHeaderValue(mime);
|
||||
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
|
||||
{
|
||||
Name = "\"file\"",
|
||||
FileName = $"\"{Random.Shared.NextInt64()}\"",
|
||||
};
|
||||
|
||||
MultipartFormDataContent form = new MultipartFormDataContent();
|
||||
form.Add(content);
|
||||
|
||||
HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, "/api/v1/media");
|
||||
req.Content = form;
|
||||
|
||||
return (await Retry<Attachment>(req))!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reposts/boosts/shares a status.
|
||||
/// </summary>
|
||||
|
|
Loading…
Reference in a new issue