diff --git a/PublishHelperBot/Environment.fs b/PublishHelperBot/Environment.fs index b0468cc..6d5d9ab 100644 --- a/PublishHelperBot/Environment.fs +++ b/PublishHelperBot/Environment.fs @@ -2,7 +2,7 @@ module PublishHelperBot.Environment open System open System.IO -open Newtonsoft.Json +open System.Text.Json open Serilog [] @@ -20,7 +20,7 @@ type public BotConfig = { } let private readConfig = - File.ReadAllText >> JsonConvert.DeserializeObject + File.ReadAllText >> JsonSerializer.Deserialize let public createConfig (name: string) = match Environment.GetEnvironmentVariable(name) with diff --git a/PublishHelperBot/PublishHelperBot.fsproj b/PublishHelperBot/PublishHelperBot.fsproj index 2a5225a..9a239a8 100644 --- a/PublishHelperBot/PublishHelperBot.fsproj +++ b/PublishHelperBot/PublishHelperBot.fsproj @@ -7,6 +7,7 @@ + diff --git a/PublishHelperBot/Telegram.fs b/PublishHelperBot/Telegram.fs index 5685edc..c9c1f47 100644 --- a/PublishHelperBot/Telegram.fs +++ b/PublishHelperBot/Telegram.fs @@ -123,7 +123,7 @@ module BotUpdateType = module TgService = type private Msg = | Ping - | PostVideo of url: string * savePath: string * externalId: Guid + | PostVideo of PostVideoArgs | PostRelay of RelayArgs | PostMessageToAdminChat of text: string @@ -198,32 +198,55 @@ module TgService = return! loop () - | PostVideo (url, savePath, externalId) -> + | PostVideo args -> try - Logging.logger.Information("Reading file path = {path}", savePath) - use file = File.OpenRead(savePath) + Logging.logger.Information("PostVideo args = {args}", args) + Logging.logger.Information("Reading file path = {path}", args.SavePath) + use file = File.OpenRead(args.SavePath) if (file.Length / 1024L / 1024L) < 50L then let input = InputOnlineFile(file, Path.GetRandomFileName()) - let caption = $"Source: {url}" + let caption = $"Source: {args.Url}" Logging.logger.Information( "Sending video to channel, channelId = {channelId}, caption = {caption}", config.ChannelId, caption) - do! config.Client.SendVideoAsync( - config.ChannelId, - input, - caption = caption + + let dimensions = + args.Width + |> Option.bind (fun w -> + args.Height + |> Option.map (fun h -> (w, h)) ) + + let sendVideo = + match dimensions with + | Some (width, height) -> + config.Client.SendVideoAsync( + config.ChannelId, + input, + caption = caption, + width = width, + height = height + ) + + | None -> + config.Client.SendVideoAsync( + config.ChannelId, + input, + caption = caption + ) + + do! sendVideo |> Async.AwaitTask |> Async.Catch |> Async.Ignore else - inbox.Post(PostMessageToAdminChat($"Да блять, видео вышло больше 50мб: {externalId}")) + inbox.Post(PostMessageToAdminChat($"Да блять, видео вышло больше 50мб: {args.ExternalId}")) finally - Logging.logger.Information("Deleting file path = {path}", savePath) - File.Delete(savePath) + Logging.logger.Information("Deleting file path = {path}", args.SavePath) + File.Delete(args.SavePath) - match! config.YoutubeDlClient.CleanJob(externalId) with + match! config.YoutubeDlClient.CleanJob(args.ExternalId) with | Ok _ -> () | Error _ -> () return! loop () @@ -243,8 +266,8 @@ module TgService = member this.PostMessageToAdminChat(text) = inbox.Post(PostMessageToAdminChat(text)) - member this.PostVideo(url, savePath, externalId) = - inbox.Post(PostVideo(url, savePath, externalId)) } + member this.PostVideo(args) = + inbox.Post(PostVideo(args)) } [] module TgUpdateHandler = diff --git a/PublishHelperBot/Types.fs b/PublishHelperBot/Types.fs index eef7373..75b3582 100644 --- a/PublishHelperBot/Types.fs +++ b/PublishHelperBot/Types.fs @@ -1,26 +1,48 @@ module PublishHelperBot.Types open System +open System.Text.Json.Serialization open Telegram.Bot open Telegram.Bot.Types type ConfigChatId = int64 type CreateYoutubeDlJob = { - url: string - savePath: string + [] + Url: string + [] + SavePath: string } type CreateYoutubeDlJobSuccess = { - task: Guid + [] + Task: Guid +} + +type YoutubeDlInfoDict = { + [] + Title: string option + [] + Height: int option + [] + Width: int option +} + +type YoutubeDlStateInfo = { + [] + InfoDict: YoutubeDlInfoDict option } type YoutubeDlStateResponse = { - state: string + [] + State: string + [] + VideoInfo: YoutubeDlStateInfo option } type YoutubeDlError = { - message: string + [] + Message: string } type CreateJobResult = Result @@ -70,8 +92,17 @@ type BotUpdateType = type ITgUpdateHandler = abstract member PostUpdate: Update -> unit +type PostVideoArgs = { + Url: string + SavePath: string + ExternalId: Guid + Title: string option + Width: int option + Height: int option +} + type ITgService = abstract member PostRelay: args: RelayArgs -> unit abstract member PostMessageToAdminChat: text: string -> unit abstract member Ping: unit -> unit - abstract member PostVideo: url: string * savePath: string * externalId: Guid -> unit \ No newline at end of file + abstract member PostVideo: PostVideoArgs -> unit \ No newline at end of file diff --git a/PublishHelperBot/YoutubeDl.fs b/PublishHelperBot/YoutubeDl.fs index 695d483..7303d49 100644 --- a/PublishHelperBot/YoutubeDl.fs +++ b/PublishHelperBot/YoutubeDl.fs @@ -5,9 +5,9 @@ open System.Collections.Generic open System.IO open System.Net.Http open System.Text +open System.Text.Json open System.Threading.Tasks open Microsoft.FSharp.Core -open Newtonsoft.Json open PublishHelperBot.Environment open PublishHelperBot.Types @@ -57,13 +57,13 @@ module YoutubeDlClient = match res.IsSuccessStatusCode with | true -> Logging.logger.Information("Response OK") - Ok (JsonConvert.DeserializeObject<'TRes>(content)) + Ok (JsonSerializer.Deserialize<'TRes>(content)) | false -> Logging.logger.Error("Response network error") - Error { message = "Unknown network error" } + Error { Message = "Unknown network error" } with ex -> Logging.logger.Error(ex, "Youtube api error") - return Error { message = ex.Message } + return Error { Message = ex.Message } } |> Async.AwaitTask let private createInbox(config: YoutubeDlClientConfig) = MailboxProcessor.Start(fun inbox -> @@ -74,7 +74,7 @@ module YoutubeDlClient = Logging.logger.Information("Received youtube api create job") async { try - let json = args |> JsonConvert.SerializeObject + let json = args |> JsonSerializer.Serialize Logging.logger.Information("Sending create job = {Job}", json) use content = new StringContent(json, Encoding.UTF8, "application/json") let! result = @@ -86,7 +86,7 @@ module YoutubeDlClient = with ex -> Logging.logger.Error(ex, "Failed to create youtube api job") tcs.SetResult(Error { - message = ex.Message + Message = ex.Message }) } |> Async.Start @@ -110,7 +110,7 @@ module YoutubeDlClient = with ex -> Logging.logger.Error(ex, "Failed to check youtube api job") tcs.SetResult(Error { - message = ex.Message + Message = ex.Message }) } |> Async.Start @@ -133,7 +133,7 @@ module YoutubeDlClient = with ex -> Logging.logger.Error(ex, "Failed to clean youtube api job") tcs.SetResult(Error { - message = ex.Message + Message = ex.Message }) } |> Async.Start @@ -182,18 +182,18 @@ module YoutubeDlService = Logging.logger.Information("Sending create job to youtube client, job = {job}", job.InternalId) let! result = client.CreateJob { - url = job.Url - savePath = job.SavePath + Url = job.Url + SavePath = job.SavePath } match result with | Ok task -> Logging.logger.Information( "Created job on youtube client = {job}, externalId = {externalId}", job.InternalId, - task.task) + task.Task) let updated = { job with - State = JobState.Awaiting task.task + State = JobState.Awaiting task.Task } return Some updated @@ -201,7 +201,7 @@ module YoutubeDlService = Logging.logger.Error( "Failed to create job on client = {job}, message = {message}", job.InternalId, - e.message) + e.Message) return None } @@ -275,11 +275,21 @@ module YoutubeDlService = | Awaiting externalId -> Logging.logger.Information("Checking job = {job}", externalId) - let! task = youtubeDlClient.CheckJob(externalId) - match task with - | Ok x when x.state.Equals("Finished", StringComparison.OrdinalIgnoreCase) -> + let! checkResult = youtubeDlClient.CheckJob(externalId) + match checkResult with + | Ok x when x.State.Equals("Finished", StringComparison.OrdinalIgnoreCase) -> Logging.logger.Information("Sending post video from job = {job}", externalId) - tgService.PostVideo(job.Url, job.SavePath, externalId) + let infoDict = + x.VideoInfo |> Option.bind (fun v -> v.InfoDict) + let args = { + Url = job.Url + SavePath = job.SavePath + ExternalId = externalId + Title = infoDict |> Option.bind (fun i -> i.Title) + Width = infoDict |> Option.bind (fun i -> i.Width) + Height = infoDict |> Option.bind (fun i -> i.Height) + } + tgService.PostVideo(args) postCheck() return! loop jobQueue None @@ -287,7 +297,7 @@ module YoutubeDlService = Logging.logger.Error( "Failed to receive video from youtube client, job = {job}, message = {message}", externalId, - e.message) + e.Message) Logging.logger.Information("Deleting file path = {path}", job.SavePath) File.Delete(job.SavePath) return! loop jobQueue None diff --git a/youtube-dl-api/youtube_dl_api/__init__.py b/youtube-dl-api/youtube_dl_api/__init__.py index f518be8..d8f4bb3 100644 --- a/youtube-dl-api/youtube_dl_api/__init__.py +++ b/youtube-dl-api/youtube_dl_api/__init__.py @@ -22,7 +22,7 @@ def report_state(id: str): def load_video(url: str, file_path: str, id: str): try: opts = { - "format": 'best[height<=480][ext=mp4]/best[ext=mp4]', + "format": 'best[filesize<=50M][ext=mp4]/best[height<=480][ext=mp4]/best[ext=mp4]', "quiet": True, "outtmpl": file_path, "progress_hooks": [report_state(id)]