-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
26c997a
commit bb73a32
Showing
22 changed files
with
4,458 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
266 changes: 266 additions & 0 deletions
266
OneShelf.Videos/OneShelf.Videos.BusinessLogic/Services/Service4.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
using System.Text.Json; | ||
using System.Text.Json.Serialization; | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
using Newtonsoft.Json; | ||
using OneShelf.Videos.BusinessLogic.Models; | ||
using OneShelf.Videos.Database; | ||
using OneShelf.Videos.Database.Models; | ||
using OneShelf.Videos.Database.Models.Enums; | ||
using TL; | ||
using WTelegram; | ||
using Document = TL.Document; | ||
|
||
namespace OneShelf.Videos.BusinessLogic.Services; | ||
|
||
public class Service4(IOptions<VideosOptions> options, ILogger<Service4> logger, VideosDatabase videosDatabase, TelegramLoggerInitializer _) : IDisposable | ||
{ | ||
private byte[]? _session; | ||
|
||
public async Task Try() | ||
{ | ||
await using var client = await Login(); | ||
|
||
var allChats = await client.Messages_GetAllChats(); | ||
|
||
foreach (var chatId in options.Value.TelegramChatIds) | ||
{ | ||
var chat = allChats.chats[chatId]; | ||
|
||
await ProcessChat(client, chat); | ||
} | ||
} | ||
|
||
private async Task ProcessChat(Client client, ChatBase chat) | ||
{ | ||
var inputPeer = chat.ToInputPeer(); | ||
|
||
var messages = await ReadAllMessages(client, inputPeer); | ||
// await File.WriteAllTextAsync("all.json", JsonConvert.SerializeObject(messages, Formatting.Indented)); | ||
|
||
await LoadStories(client, inputPeer, messages); | ||
|
||
var topics = await GetTopicsAndMedia(messages); | ||
|
||
//await client.DownloadFileAsync(topics[0].media[0].document.ToFileLocation(topics[0].media[0].document.LargestThumbSize), outputStream) | ||
|
||
logger.LogInformation(string.Join(Environment.NewLine, topics.Select(x => $"{x.Key}={x.Value.name} (d: {x.Value.media.Count(x => x.document != null)}, p: {x.Value.media.Count(x => x.photo != null)})"))); | ||
|
||
await Save(chat, topics); | ||
} | ||
|
||
private async Task Save(ChatBase chat, Dictionary<int, (string name, List<(Document? document, Photo? photo, Message message, string mediaFlags)> media)> topics) | ||
{ | ||
var liveChat = await videosDatabase.LiveChats.Include(x => x.Topics).ThenInclude(x => x.Mediae).SingleOrDefaultAsync(x => x.Id == chat.ID); | ||
if (liveChat == null) | ||
{ | ||
liveChat = new() | ||
{ | ||
Id = chat.ID, | ||
Topics = new List<LiveTopic>(), | ||
}; | ||
|
||
videosDatabase.LiveChats.Add(liveChat); | ||
} | ||
|
||
liveChat.Title = chat.Title; | ||
|
||
foreach (var topic in topics) | ||
{ | ||
var liveTopic = liveChat.Topics.SingleOrDefault(x => x.Id == topic.Key); | ||
if (liveTopic == null) | ||
{ | ||
liveTopic = new() | ||
{ | ||
Id = topic.Key, | ||
Mediae = new List<LiveMedia>(), | ||
}; | ||
|
||
liveChat.Topics.Add(liveTopic); | ||
} | ||
|
||
liveTopic.Title = topic.Value.name; | ||
|
||
var liveMediae = liveTopic.Mediae.ToDictionary(x => x.Id); | ||
foreach (var media in topic.Value.media) | ||
{ | ||
var liveMedia = liveMediae.GetValueOrDefault(media.message.ID); | ||
if (liveMedia == null) | ||
{ | ||
liveMedia = new() | ||
{ | ||
Id = media.message.ID, | ||
}; | ||
|
||
liveTopic.Mediae.Add(liveMedia); | ||
} | ||
|
||
liveMedia.MessageDate = media.message.fwd_from?.date ?? media.message.Date; | ||
liveMedia.IsForwarded = media.message.fwd_from != null; | ||
liveMedia.MediaType = media.message.media.GetType().ToString(); | ||
liveMedia.MediaFlags = media.mediaFlags; | ||
|
||
if (media.document is {} document) | ||
{ | ||
liveMedia.Type = LiveMediaType.Document; | ||
liveMedia.MediaDate = document.date; | ||
liveMedia.MediaId = document.ID; | ||
liveMedia.FileName = document.Filename; | ||
liveMedia.Flags = document.flags.ToString(); | ||
liveMedia.MimeType = document.mime_type; | ||
liveMedia.Size = document.size; | ||
liveMedia.DocumentAttributes = JsonConvert.SerializeObject(document.attributes); | ||
liveMedia.DocumentAttributeTypes = string.Join(", ", document.attributes.Select(a => a.GetType())); | ||
|
||
var attributeVideo = document.attributes.OfType<DocumentAttributeVideo>().SingleOrDefault(); | ||
if (attributeVideo != null) | ||
{ | ||
liveMedia.Width = attributeVideo.w; | ||
liveMedia.Height = attributeVideo.h; | ||
liveMedia.Duration = attributeVideo.duration; | ||
liveMedia.VideoFlags = attributeVideo.flags.ToString(); | ||
} | ||
} | ||
else if (media.photo is {} photo) | ||
{ | ||
liveMedia.Type = LiveMediaType.Photo; | ||
liveMedia.MediaDate = photo.date; | ||
liveMedia.MediaId = photo.ID; | ||
liveMedia.Flags = photo.flags.ToString(); | ||
liveMedia.Size = photo.LargestPhotoSize.FileSize; | ||
liveMedia.Width = photo.LargestPhotoSize.Width; | ||
liveMedia.Height = photo.LargestPhotoSize.Height; | ||
} | ||
else | ||
{ | ||
throw new("A media should either be a document or a photo."); | ||
} | ||
} | ||
} | ||
|
||
await videosDatabase.SaveChangesAsync(); | ||
} | ||
|
||
private async Task LoadStories(Client client, InputPeer inputPeer, List<MessageBase> messages) | ||
{ | ||
foreach (var message in messages) | ||
{ | ||
if (message is Message { media: MessageMediaStory { story: null } story }) | ||
{ | ||
story.story = (await client.Stories_GetStoriesByID(new InputPeerUserFromMessage { peer = inputPeer, msg_id = message.ID, user_id = story.peer.ID }, story.id)).stories.Single(); | ||
} | ||
} | ||
} | ||
|
||
private static async Task<Dictionary<int, (string name, List<(Document? document, Photo? photo, Message message, string mediaFlags)> media)>> GetTopicsAndMedia(List<MessageBase> messages) | ||
{ | ||
var topics = new Dictionary<int, (string name, List<(Document? document, Photo? photo, Message message, string mediaFlags)> media)> | ||
{ | ||
{ 0, ("General", new()) }, | ||
}; | ||
|
||
foreach (var messageBase in messages.OrderBy(x => x.ID)) | ||
{ | ||
// getting topic id | ||
int? topicId = null; | ||
if (messageBase.ReplyTo is MessageReplyHeader { flags: MessageReplyHeader.Flags flags } header) | ||
{ | ||
if (flags.HasFlag(MessageReplyHeader.Flags.has_reply_to_top_id)) | ||
{ | ||
topicId = header.reply_to_top_id; | ||
} | ||
else if (flags.HasFlag(MessageReplyHeader.Flags.has_reply_to_msg_id)) | ||
{ | ||
topicId = header.reply_to_msg_id; | ||
} | ||
} | ||
|
||
if (topicId.HasValue && !topics.ContainsKey(topicId.Value)) topicId = null; | ||
|
||
// handling the topics collection | ||
if (messageBase is MessageService { action: MessageActionTopicCreate messageActionTopicCreate }) | ||
{ | ||
topics.Add(messageBase.ID, (messageActionTopicCreate.title, new())); | ||
} | ||
|
||
if (messageBase is MessageService { action: MessageActionTopicEdit messageActionTopicEdit }) | ||
{ | ||
topics[topicId!.Value] = (messageActionTopicEdit.title, topics[topicId.Value].media); | ||
} | ||
|
||
(Document? document, Photo? photo, Message message, string mediaFlags)? media = messageBase switch | ||
{ | ||
Message { media: MessageMediaDocument { document: Document document, flags: { } mediaFlags } } message => (document, null, message, mediaFlags.ToString()), | ||
Message { media: MessageMediaPhoto { photo: Photo photo, flags: { } mediaFlags } } message => (null, photo, message, mediaFlags.ToString()), | ||
Message { media: MessageMediaStory { story: StoryItem { media: MessageMediaDocument { document: Document document, flags: { } mediaFlags } } } } message => (document, null, message, mediaFlags.ToString()), | ||
Message { media: MessageMediaStory { story: StoryItem { media: MessageMediaPhoto { photo: Photo photo, flags: { } mediaFlags } } } } message => (null, photo, message, mediaFlags.ToString()), | ||
_ => default, | ||
}; | ||
|
||
if (media.HasValue) | ||
topics[topicId ?? 0].media.Add(media.Value); | ||
} | ||
|
||
return topics; | ||
} | ||
|
||
private static async Task<List<MessageBase>> ReadAllMessages(Client client, InputPeer inputPeer) | ||
{ | ||
var offsetId = 0; | ||
List<MessageBase> messages = new(); | ||
int? count = null; | ||
while (true) | ||
{ | ||
var z = await client.Messages_GetHistory(inputPeer, offset_id: offsetId); | ||
if (!z.Messages.Any()) break; | ||
count ??= z.Count; | ||
messages.AddRange(z.Messages); | ||
offsetId = z.Messages.Min(x => x.ID); | ||
} | ||
|
||
if (messages.Count != count) throw new("Could not read all messages."); | ||
return messages; | ||
} | ||
|
||
private async Task<Client> Login() | ||
{ | ||
Client? client = null; | ||
try | ||
{ | ||
client = new( | ||
what => what switch | ||
{ | ||
"api_id" => options.Value.TelegramApiId, | ||
"api_hash" => options.Value.TelegramApiHash, | ||
"phone_number" => options.Value.TelegramPhoneNumber, | ||
"verification_code" => null, | ||
"password" => "secret!", // if user has enabled 2FA | ||
_ => null, // let WTelegramClient decide the default config | ||
}, | ||
File.Exists(options.Value.TelegramAuthPath) | ||
? await File.ReadAllBytesAsync(options.Value.TelegramAuthPath) | ||
: null, | ||
x => _session = x); | ||
|
||
var myself = await client.LoginUserIfNeeded(); | ||
|
||
logger.LogInformation("We are logged-in as {myself} (id {id})", myself, myself.id); | ||
return client; | ||
} | ||
catch | ||
{ | ||
if (client != null) await client.DisposeAsync(); | ||
throw; | ||
} | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
if (_session != null) | ||
{ | ||
File.WriteAllBytes(options.Value.TelegramAuthPath, _session); | ||
logger.LogInformation("Successfully disposed the telegram client session."); | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
OneShelf.Videos/OneShelf.Videos.BusinessLogic/Services/TelegramLogger.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace OneShelf.Videos.BusinessLogic.Services; | ||
|
||
public class TelegramLoggerInitializer | ||
{ | ||
public TelegramLoggerInitializer(ILogger<Service4> logger) | ||
{ | ||
WTelegram.Helpers.Log = (logLevel, message) => logger.Log((LogLevel)logLevel, message); | ||
} | ||
} |
Oops, something went wrong.