telegram and instagram wrappers, DtsodFile
This commit is contained in:
parent
adbebc37ec
commit
327d06b3d0
54
Config.cs
54
Config.cs
@ -1,57 +1,39 @@
|
|||||||
namespace InstaFollowersOverseer;
|
namespace InstaFollowersOverseer;
|
||||||
|
|
||||||
public class Config
|
public class Config : DtsodFile
|
||||||
{
|
{
|
||||||
|
#nullable disable
|
||||||
private const string config_file="config.dtsod";
|
|
||||||
private const string config_example_file="config-example.dtsod";
|
|
||||||
|
|
||||||
public string botToken;
|
public string botToken;
|
||||||
public string instagramLogin;
|
public string instagramLogin;
|
||||||
public string instagramPassword;
|
public string instagramPassword;
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
public Config(DtsodV23 configDtsod)
|
public Config(string fileNameWithoutExt) : base(fileNameWithoutExt) { }
|
||||||
|
|
||||||
|
public override void LoadFromFile()
|
||||||
{
|
{
|
||||||
botToken = configDtsod[nameof(botToken)];
|
var dtsod = ReadDtsodFromFile(true);
|
||||||
instagramLogin = configDtsod[nameof(instagramLogin)];
|
try
|
||||||
instagramPassword = configDtsod[nameof(instagramPassword)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Config ReadFromFile()
|
|
||||||
{
|
|
||||||
if (!File.Exists(config_file))
|
|
||||||
{
|
{
|
||||||
EmbeddedResources.CopyToFile(
|
botToken = dtsod[nameof(botToken)];
|
||||||
$"{EmbeddedResourcesPrefix}.{config_example_file}",
|
instagramLogin = dtsod[nameof(instagramLogin)];
|
||||||
config_example_file);
|
instagramPassword = dtsod[nameof(instagramPassword)];
|
||||||
throw new Exception($"File {config_file} doesnt exist. You have create config. See {config_example_file}");
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception($"your {FileName} format is invalid\n"
|
||||||
|
+ $"See {FileExampleName}", innerException: ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Config(new DtsodV23(File.ReadAllText(config_file)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public DtsodV23 ToDtsod()
|
public override DtsodV23 ToDtsod()
|
||||||
{
|
{
|
||||||
var d = new DtsodV23
|
var d = new DtsodV23
|
||||||
{
|
{
|
||||||
{ nameof(botToken), botToken },
|
{ nameof(botToken), botToken },
|
||||||
{ nameof(instagramLogin), instagramLogin },
|
{ nameof(instagramLogin), instagramLogin },
|
||||||
{ nameof(instagramLogin), instagramLogin }
|
{ nameof(instagramPassword), instagramPassword }
|
||||||
};
|
};
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => ToDtsod().ToString();
|
|
||||||
|
|
||||||
public void SaveToFile()
|
|
||||||
{
|
|
||||||
File.Copy(config_file,
|
|
||||||
$"backups/{config_file}.old-"+
|
|
||||||
"{DateTime.Now.ToString(MyTimeFormat.ForFileNames)}",
|
|
||||||
true);
|
|
||||||
|
|
||||||
File.OpenWrite(config_file)
|
|
||||||
.FluentWriteString("#DtsodV23\n")
|
|
||||||
.WriteString(ToDtsod().ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
64
DtsodFile.cs
Normal file
64
DtsodFile.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace InstaFollowersOverseer;
|
||||||
|
|
||||||
|
public abstract class DtsodFile
|
||||||
|
{
|
||||||
|
public readonly string FileNameWithoutExt;
|
||||||
|
public readonly string FileName;
|
||||||
|
public readonly string FileExampleName;
|
||||||
|
|
||||||
|
public DtsodFile(string fileNameWithoutExt)
|
||||||
|
{
|
||||||
|
FileNameWithoutExt = fileNameWithoutExt;
|
||||||
|
FileName = fileNameWithoutExt + ".dtsod";
|
||||||
|
FileExampleName = fileNameWithoutExt + "-example.dtsod";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CreateBackup()
|
||||||
|
{
|
||||||
|
string backupPath=$"backups/{FileNameWithoutExt}.d/{FileNameWithoutExt}"
|
||||||
|
+DateTime.Now.ToString(MyTimeFormat.ForFileNames)+".dtsod";
|
||||||
|
Program.MainLogger.LogInfo($"creating backup if file {FileName} at path {backupPath}");
|
||||||
|
File.Copy(FileName,backupPath,false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DtsodV23 ReadDtsodFromFile(bool trhowIfFileNotFound)
|
||||||
|
{
|
||||||
|
Program.MainLogger.LogInfo($"reading file {FileName}");
|
||||||
|
EmbeddedResources.CopyToFile(
|
||||||
|
$"{EmbeddedResourcesPrefix}.{FileExampleName}",
|
||||||
|
FileExampleName);
|
||||||
|
|
||||||
|
if (!File.Exists(FileName))
|
||||||
|
{
|
||||||
|
File.WriteAllText(FileName, "#DtsodV23\n");
|
||||||
|
string message = $"file {FileName} doesnt exist, created new blank";
|
||||||
|
if (trhowIfFileNotFound)
|
||||||
|
throw new FileNotFoundException(message);
|
||||||
|
Program.MainLogger.LogWarn(message);
|
||||||
|
return new DtsodV23();
|
||||||
|
}
|
||||||
|
|
||||||
|
string fileText = File.ReadAllText(FileName);
|
||||||
|
Program.MainLogger.LogDebug(fileText);
|
||||||
|
return new DtsodV23(fileText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void LoadFromFile();
|
||||||
|
|
||||||
|
public abstract DtsodV23 ToDtsod();
|
||||||
|
|
||||||
|
public void SaveToFile()
|
||||||
|
{
|
||||||
|
Program.MainLogger.LogInfo($"saving file {FileName}");
|
||||||
|
string dtsodStr = ToDtsod().ToString();
|
||||||
|
Program.MainLogger.LogDebug(dtsodStr);
|
||||||
|
if(File.Exists(FileName))
|
||||||
|
CreateBackup();
|
||||||
|
File.OpenWrite(FileName)
|
||||||
|
.FluentWriteString("#DtsodV23\n")
|
||||||
|
.FluentWriteString(dtsodStr)
|
||||||
|
.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,17 +1,29 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<!--project info-->
|
||||||
|
<Authors>Timerix</Authors>
|
||||||
|
<Description>Telegram bot that notifies users when somebody follows/unfollows theit instagram accounts</Description>
|
||||||
|
<RepositoryType>GIT</RepositoryType>
|
||||||
|
<RepositoryUrl>https://github.com/Timerix22/InstaFollowersOverseer</RepositoryUrl>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
<!--compilation properties-->
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||||
|
<DebugType>embedded</DebugType>
|
||||||
|
<!--language features-->
|
||||||
|
<LangVersion>preview</LangVersion>
|
||||||
<ImplicitUsings>disable</ImplicitUsings>
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>preview</LangVersion>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!--third-party dependencies-->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="InstaSharper" Version="1.4.82" />
|
||||||
<PackageReference Include="Telegram.Bot" Version="18.0.0" />
|
<PackageReference Include="Telegram.Bot" Version="18.0.0" />
|
||||||
<PackageReference Include="Telegram.Bots.Extensions.Polling" Version="5.9.0" />
|
<!--PackageReference Include="Telegram.Bots.Extensions.Polling" Version="5.9.0" /-->
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!--dtlib dependencies-->
|
||||||
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<ProjectReference Include="..\DTLib\DTLib.Logging\DTLib.Logging.csproj" />
|
<ProjectReference Include="..\DTLib\DTLib.Logging\DTLib.Logging.csproj" />
|
||||||
<ProjectReference Include="..\DTLib\DTLib.Dtsod\DTLib.Dtsod.csproj" />
|
<ProjectReference Include="..\DTLib\DTLib.Dtsod\DTLib.Dtsod.csproj" />
|
||||||
@ -25,6 +37,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="resources\**\*" />
|
<None Remove="resources\**\*" />
|
||||||
<EmbeddedResource Include="resources\**\*" />
|
<EmbeddedResource Include="resources\**\*" />
|
||||||
|
<None Remove=".gitignore" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
3
InstaFollowersOverseer.sln.DotSettings.user
Normal file
3
InstaFollowersOverseer.sln.DotSettings.user
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/SweaWarningsMode/@EntryValue">ShowAndRun</s:String>
|
||||||
|
</wpf:ResourceDictionary>
|
||||||
37
Instagram/InstagramApiLogger.cs
Normal file
37
Instagram/InstagramApiLogger.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System.Net.Http;
|
||||||
|
using InstaSharper.Logger;
|
||||||
|
|
||||||
|
namespace InstaFollowersOverseer.Instagram;
|
||||||
|
|
||||||
|
public class InstagramApiLogger : IInstaLogger
|
||||||
|
{
|
||||||
|
public ContextLogger _logger = new("api", InstagramWrapper.InstagramLogger);
|
||||||
|
|
||||||
|
public void LogRequest(HttpRequestMessage r)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("http",$"request {r.Method.Method.ToUpper()} from {r.RequestUri}:\n"
|
||||||
|
+ r.Content?.ReadAsStringAsync().GetAwaiter().GetResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogRequest(Uri uri)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogResponse(HttpResponseMessage r)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("http",$"responce from " +
|
||||||
|
(r.RequestMessage!=null && r.RequestMessage.RequestUri!=null ? r.RequestMessage.RequestUri.ToString() : "unknown")
|
||||||
|
+ $" :\n "+ r.Content.ReadAsStringAsync().GetAwaiter().GetResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogException(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogInfo(string info)
|
||||||
|
{
|
||||||
|
_logger.LogInfo(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
58
Instagram/InstagramWrapper.cs
Normal file
58
Instagram/InstagramWrapper.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using InstaSharper.API;
|
||||||
|
using InstaSharper.API.Builder;
|
||||||
|
using InstaSharper.Classes;
|
||||||
|
using InstaSharper.Classes.Models;
|
||||||
|
|
||||||
|
namespace InstaFollowersOverseer.Instagram;
|
||||||
|
|
||||||
|
public static class InstagramWrapper
|
||||||
|
{
|
||||||
|
public static ContextLogger InstagramLogger = new("instagram",ParentLogger);
|
||||||
|
private static IInstaApi Api=null!;
|
||||||
|
|
||||||
|
public static async void Init()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
InstagramLogger.LogInfo("initializing instagram wrapper");
|
||||||
|
if (CurrentConfig is null)
|
||||||
|
throw new NullReferenceException("config is null");
|
||||||
|
var apiLogger = new InstagramApiLogger();
|
||||||
|
// disabling http request/responce logging
|
||||||
|
apiLogger._logger.DebugLogEnabled = false;
|
||||||
|
Api = InstaApiBuilder.CreateBuilder()
|
||||||
|
.UseLogger(apiLogger)
|
||||||
|
.SetUser(new UserSessionData
|
||||||
|
{
|
||||||
|
UserName = CurrentConfig.instagramLogin,
|
||||||
|
Password = CurrentConfig.instagramPassword
|
||||||
|
})
|
||||||
|
.SetRequestDelay(RequestDelay.FromSeconds(0, 1))
|
||||||
|
.Build();
|
||||||
|
InstagramLogger.LogInfo("instagram login starting");
|
||||||
|
var rezult= await Api.LoginAsync();
|
||||||
|
if (!rezult.Succeeded)
|
||||||
|
throw new Exception("login exception:\n" + rezult.Info + '\n' + rezult.Value);
|
||||||
|
InstagramLogger.LogInfo("instagram wrapper have initialized and connected successfully");
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) {}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
InstagramLogger.LogError("init", ex);
|
||||||
|
Program.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<InstaUser?> GetUserAsync(string usernameOrUrl)
|
||||||
|
{
|
||||||
|
// url
|
||||||
|
if (usernameOrUrl.Contains('/'))
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("get user by url");
|
||||||
|
}
|
||||||
|
|
||||||
|
// username
|
||||||
|
var u=await Api.GetUserAsync(usernameOrUrl);
|
||||||
|
return u.Succeeded ? u.Value : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
92
Program.cs
92
Program.cs
@ -2,6 +2,7 @@
|
|||||||
global using System.Threading.Tasks;
|
global using System.Threading.Tasks;
|
||||||
global using System.Linq;
|
global using System.Linq;
|
||||||
global using System.Collections.Generic;
|
global using System.Collections.Generic;
|
||||||
|
global using DTLib;
|
||||||
global using DTLib.Filesystem;
|
global using DTLib.Filesystem;
|
||||||
global using DTLib.Extensions;
|
global using DTLib.Extensions;
|
||||||
global using DTLib.Dtsod;
|
global using DTLib.Dtsod;
|
||||||
@ -10,18 +11,20 @@ global using File = DTLib.Filesystem.File;
|
|||||||
global using Directory = DTLib.Filesystem.Directory;
|
global using Directory = DTLib.Filesystem.Directory;
|
||||||
global using Path = DTLib.Filesystem.Path;
|
global using Path = DTLib.Filesystem.Path;
|
||||||
global using static InstaFollowersOverseer.SharedData;
|
global using static InstaFollowersOverseer.SharedData;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Telegram.Bot;
|
|
||||||
using Telegram.Bot.Polling;
|
|
||||||
using Telegram.Bot.Types;
|
|
||||||
using Telegram.Bot.Types.Enums;
|
|
||||||
|
|
||||||
namespace InstaFollowersOverseer;
|
namespace InstaFollowersOverseer;
|
||||||
|
|
||||||
static class Program
|
static class Program
|
||||||
{
|
{
|
||||||
|
public static readonly ContextLogger MainLogger = new("main", ParentLogger);
|
||||||
|
|
||||||
|
private static CancellationTokenSource MainCancel=new();
|
||||||
|
public static CancellationToken MainCancelToken = MainCancel.Token;
|
||||||
|
public static void Stop() => MainCancel.Cancel();
|
||||||
|
|
||||||
|
|
||||||
static void Main()
|
static void Main()
|
||||||
{
|
{
|
||||||
Console.InputEncoding=Encoding.UTF8;
|
Console.InputEncoding=Encoding.UTF8;
|
||||||
@ -29,90 +32,31 @@ static class Program
|
|||||||
DTLibInternalLogging.SetLogger(MainLogger.ParentLogger);
|
DTLibInternalLogging.SetLogger(MainLogger.ParentLogger);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
config = Config.ReadFromFile();
|
MainLogger.LogInfo("reading config");
|
||||||
userSettings = UserSettings.ReadFromFile();
|
CurrentConfig.LoadFromFile();
|
||||||
|
CurrentUsersData.LoadFromFile();
|
||||||
|
|
||||||
CancellationTokenSource mainCancel = new CancellationTokenSource();
|
|
||||||
Console.CancelKeyPress += (_, e) =>
|
Console.CancelKeyPress += (_, e) =>
|
||||||
{
|
{
|
||||||
mainCancel.Cancel();
|
Stop();
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
MainLogger.LogInfo("all have cancelled");
|
MainLogger.LogInfo("all have cancelled");
|
||||||
e.Cancel = false;
|
e.Cancel = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
var bot = new TelegramBotClient(config.botToken, new HttpClient());
|
Instagram.InstagramWrapper.Init();
|
||||||
var receiverOptions = new ReceiverOptions
|
Telegram.TelegramWrapper.Init();
|
||||||
{
|
|
||||||
AllowedUpdates = { }, // receive all update types
|
|
||||||
|
|
||||||
};
|
Task.Delay(-1, MainCancel.Token).GetAwaiter().GetResult();
|
||||||
bot.StartReceiving(BotApiUpdateHandler, BotApiExceptionHandler, receiverOptions, mainCancel.Token);
|
|
||||||
|
|
||||||
Task.Delay(-1, mainCancel.Token).GetAwaiter().GetResult();
|
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
}
|
}
|
||||||
|
catch (OperationCanceledException) {}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
MainLogger.LogError(ex);
|
MainLogger.LogError(ex);
|
||||||
}
|
}
|
||||||
|
CurrentConfig.SaveToFile();
|
||||||
|
CurrentUsersData.SaveToFile();
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ContextLogger botLogger = new ContextLogger("bot", MainLogger.ParentLogger);
|
|
||||||
|
|
||||||
static async Task BotApiUpdateHandler(ITelegramBotClient bot, Update update, CancellationToken cls)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
switch (update.Type)
|
|
||||||
{
|
|
||||||
case UpdateType.Message:
|
|
||||||
{
|
|
||||||
var message = update.Message!;
|
|
||||||
if (message.Text!.StartsWith('/'))
|
|
||||||
{
|
|
||||||
botLogger.LogInfo($"user {message.Chat.Id} sent command {message.Text}");
|
|
||||||
var spl = message.Text.SplitToList(' ');
|
|
||||||
string command = spl[0].Substring(1);
|
|
||||||
spl.RemoveAt(0);
|
|
||||||
string[] args = spl.ToArray();
|
|
||||||
switch (command)
|
|
||||||
{
|
|
||||||
case "start":
|
|
||||||
await bot.SendTextMessageAsync(message.Chat, "hi");
|
|
||||||
break;
|
|
||||||
case "oversee":
|
|
||||||
break;
|
|
||||||
// default:
|
|
||||||
// throw new BotCommandException(command, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else botLogger.LogDebug($"message recieved: {message.Text}");
|
|
||||||
|
|
||||||
break;
|
|
||||||
} /*
|
|
||||||
case UpdateType.EditedMessage:
|
|
||||||
break;
|
|
||||||
case UpdateType.InlineQuery:
|
|
||||||
break;
|
|
||||||
case UpdateType.ChosenInlineResult:
|
|
||||||
break;
|
|
||||||
case UpdateType.CallbackQuery:
|
|
||||||
break;*/
|
|
||||||
default:
|
|
||||||
botLogger.LogWarn($"unknown update type: {update.Type}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
botLogger.LogWarn("UpdateHandler", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static Task BotApiExceptionHandler(ITelegramBotClient bot, Exception ex, CancellationToken cls)
|
|
||||||
{
|
|
||||||
botLogger.LogError(ex);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -4,13 +4,10 @@ public static class SharedData
|
|||||||
{
|
{
|
||||||
internal const string EmbeddedResourcesPrefix = "InstaFollowersOverseer.resources";
|
internal const string EmbeddedResourcesPrefix = "InstaFollowersOverseer.resources";
|
||||||
|
|
||||||
#nullable disable
|
internal static Config CurrentConfig = new("config");
|
||||||
internal static Config config;
|
internal static UsersData CurrentUsersData = new("users-data");
|
||||||
internal static UserSettings userSettings;
|
|
||||||
#nullable enable
|
public static readonly CompositeLogger ParentLogger = new(
|
||||||
|
new ConsoleLogger(),
|
||||||
public static readonly ContextLogger MainLogger = new ContextLogger("main",new CompositeLogger(
|
new FileLogger("logs", "InstaFollowersOverseer"));
|
||||||
new ConsoleLogger(),
|
|
||||||
new FileLogger("logs","InstaFollowersOverseer"))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
134
Telegram/TelegramWrapper.cs
Normal file
134
Telegram/TelegramWrapper.cs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using Telegram.Bot;
|
||||||
|
using Telegram.Bot.Polling;
|
||||||
|
using Telegram.Bot.Types;
|
||||||
|
using Telegram.Bot.Types.Enums;
|
||||||
|
using InstaFollowersOverseer.Instagram;
|
||||||
|
|
||||||
|
namespace InstaFollowersOverseer.Telegram;
|
||||||
|
|
||||||
|
public static class TelegramWrapper
|
||||||
|
{
|
||||||
|
private static ContextLogger TelegramLogger = new("telegram", ParentLogger);
|
||||||
|
private static TelegramBotClient Bot=null!;
|
||||||
|
|
||||||
|
public static async void Init()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TelegramLogger.LogInfo("initializing telegram wrapper");
|
||||||
|
if (CurrentConfig is null)
|
||||||
|
throw new NullReferenceException("config is null");
|
||||||
|
Bot = new TelegramBotClient(CurrentConfig.botToken, new HttpClient());
|
||||||
|
await Bot.SetMyCommandsAsync(new BotCommand[]
|
||||||
|
{
|
||||||
|
new() { Command = "start", Description = "starts the bot"},
|
||||||
|
// new() { Command = "help", Description = "shows commands list" },
|
||||||
|
new() { Command = "oversee", Description = "[instagram username] - " +
|
||||||
|
"enables notifications about instagram user's followers" },
|
||||||
|
new() { Command = "list", Description = "shows list of overseeing instagram users" }
|
||||||
|
});
|
||||||
|
var receiverOptions = new ReceiverOptions
|
||||||
|
{
|
||||||
|
// AllowedUpdates = { }, // receive all update types
|
||||||
|
};
|
||||||
|
TelegramLogger.LogInfo("bot starting recieving long polls");
|
||||||
|
Bot.StartReceiving(BotApiUpdateHandler, BotApiExceptionHandler, receiverOptions, Program.MainCancelToken);
|
||||||
|
TelegramLogger.LogInfo("telegram wrapper have initialized successfully");
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) {}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
TelegramLogger.LogError("init", ex);
|
||||||
|
Program.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Task BotApiExceptionHandler(ITelegramBotClient bot, Exception ex, CancellationToken cls)
|
||||||
|
{
|
||||||
|
TelegramLogger.LogError(ex);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async Task SendInfoReply(string text, Message replyToMessage)
|
||||||
|
{
|
||||||
|
TelegramLogger.LogInfo(text);
|
||||||
|
await Bot.SendTextMessageAsync(replyToMessage.Chat, text,
|
||||||
|
replyToMessageId: replyToMessage.MessageId,
|
||||||
|
parseMode:ParseMode.MarkdownV2);
|
||||||
|
}
|
||||||
|
static async Task SendErrorReply(string text, Message replyToMessage)
|
||||||
|
{
|
||||||
|
TelegramLogger.LogWarn(text);
|
||||||
|
await Bot.SendTextMessageAsync(replyToMessage.Chat, "error: "+text,
|
||||||
|
replyToMessageId: replyToMessage.MessageId,
|
||||||
|
parseMode:ParseMode.MarkdownV2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task BotApiUpdateHandler(ITelegramBotClient bot, Update update, CancellationToken cls)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (update.Type)
|
||||||
|
{
|
||||||
|
case UpdateType.Message:
|
||||||
|
{
|
||||||
|
var message = update.Message!;
|
||||||
|
if (message.Text!.StartsWith('/'))
|
||||||
|
{
|
||||||
|
TelegramLogger.LogInfo($"user {message.Chat.Id} sent command {message.Text}");
|
||||||
|
var spl = message.Text.SplitToList(' ');
|
||||||
|
string command = spl[0].Substring(1);
|
||||||
|
spl.RemoveAt(0);
|
||||||
|
string[] args = spl.ToArray();
|
||||||
|
await ExecCommandAsync(command, args, message);
|
||||||
|
}
|
||||||
|
else TelegramLogger.LogDebug($"message recieved: {message.Text}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*case UpdateType.InlineQuery:
|
||||||
|
break;
|
||||||
|
case UpdateType.ChosenInlineResult:
|
||||||
|
break;
|
||||||
|
case UpdateType.CallbackQuery:
|
||||||
|
break;*/
|
||||||
|
default:
|
||||||
|
TelegramLogger.LogWarn($"unknown update type: {update.Type}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) {}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
TelegramLogger.LogWarn("UpdateHandler", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task ExecCommandAsync(string command, string[] args, Message message)
|
||||||
|
{
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case "start":
|
||||||
|
await Bot.SendTextMessageAsync(message.Chat, "hi");
|
||||||
|
break;
|
||||||
|
case "oversee":
|
||||||
|
{
|
||||||
|
string usernameOrUrl = args[0];
|
||||||
|
await SendInfoReply($"searching for instagram user <{usernameOrUrl}>", message);
|
||||||
|
var user = await InstagramWrapper.GetUserAsync(usernameOrUrl);
|
||||||
|
if (user is null)
|
||||||
|
{
|
||||||
|
await SendErrorReply($"user **{usernameOrUrl}** doesnt exist", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CurrentUsersData.AddOrSet(message.Chat.Id.ToString(), new InstagramObservableParams(usernameOrUrl));
|
||||||
|
CurrentUsersData.SaveToFile();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
await SendErrorReply("ivalid command", message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
114
UserSettings.cs
114
UserSettings.cs
@ -1,114 +0,0 @@
|
|||||||
namespace InstaFollowersOverseer;
|
|
||||||
|
|
||||||
public class UserSettings
|
|
||||||
{
|
|
||||||
private const string user_settings_file="user-settings.dtsod";
|
|
||||||
private const string user_settings_example_file="user-settings-example.dtsod";
|
|
||||||
|
|
||||||
private Dictionary<string, List<InstagramObservableParams>> userSettings=new();
|
|
||||||
|
|
||||||
private UserSettings()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserSettings(DtsodV23 _userSettings)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
foreach (var uset in _userSettings)
|
|
||||||
{
|
|
||||||
string telegramUserId = uset.Key;
|
|
||||||
|
|
||||||
List<InstagramObservableParams> oparams = new List<InstagramObservableParams>();
|
|
||||||
foreach (DtsodV23 _overseeParams in uset.Value)
|
|
||||||
oparams.Add(new InstagramObservableParams(_overseeParams));
|
|
||||||
|
|
||||||
userSettings.Add(telegramUserId, oparams);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new Exception($"your {user_settings_file} format is invalid\n"
|
|
||||||
+ $"See {user_settings_example_file}", innerException:ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UserSettings ReadFromFile()
|
|
||||||
{
|
|
||||||
EmbeddedResources.CopyToFile(
|
|
||||||
$"{EmbeddedResourcesPrefix}.{user_settings_example_file}",
|
|
||||||
user_settings_example_file);
|
|
||||||
|
|
||||||
if (File.Exists(user_settings_file))
|
|
||||||
return new UserSettings(new DtsodV23(File.ReadAllText(user_settings_file)));
|
|
||||||
|
|
||||||
MainLogger.LogWarn($"file {user_settings_file} doesnt exist, creating new");
|
|
||||||
File.WriteAllText(user_settings_file,"#DtsodV23\n");
|
|
||||||
return new UserSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DtsodV23 ToDtsod()
|
|
||||||
{
|
|
||||||
var b = new DtsodV23();
|
|
||||||
foreach (var userS in userSettings)
|
|
||||||
b.Add(userS.Key,
|
|
||||||
userS.Value.Select(iop =>
|
|
||||||
iop.ToDtsod()
|
|
||||||
).ToList());
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() => ToDtsod().ToString();
|
|
||||||
|
|
||||||
public void SaveToFile()
|
|
||||||
{
|
|
||||||
File.Copy(user_settings_file,
|
|
||||||
$"backups/{user_settings_file}.old-"+
|
|
||||||
"{DateTime.Now.ToString(MyTimeFormat.ForFileNames)}",
|
|
||||||
true);
|
|
||||||
|
|
||||||
File.OpenWrite(user_settings_file)
|
|
||||||
.FluentWriteString("#DtsodV23\n")
|
|
||||||
.WriteString(ToDtsod().ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<InstagramObservableParams> Get(string telegramUserId)
|
|
||||||
{
|
|
||||||
if (!userSettings.TryGetValue(telegramUserId, out var overseeParams))
|
|
||||||
throw new Exception($"there is no settings for user {telegramUserId}");
|
|
||||||
return overseeParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddOrSet(string telegramUserId, InstagramObservableParams instagramObservableParams)
|
|
||||||
{
|
|
||||||
// Add
|
|
||||||
// doesnt contain settings for telegramUserId
|
|
||||||
if (!userSettings.TryGetValue(telegramUserId, out var thisUserSettings))
|
|
||||||
{
|
|
||||||
userSettings.Add(telegramUserId, new (){ instagramObservableParams });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set
|
|
||||||
// settings for telegramUserId contain InstagramObservableParams with instagramObservableParams.instagramUserId
|
|
||||||
for (var i = 0; i < thisUserSettings.Count; i++)
|
|
||||||
{
|
|
||||||
if (thisUserSettings[i].instagramUserId == instagramObservableParams.instagramUserId)
|
|
||||||
{
|
|
||||||
thisUserSettings[i] = instagramObservableParams;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add
|
|
||||||
// doesnt contain InstagramObservableParams with instagramObservableParams.instagramUserId
|
|
||||||
thisUserSettings.Add(instagramObservableParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddOrSet(string telegramUserId, IEnumerable<InstagramObservableParams> instagramObservableParams)
|
|
||||||
{
|
|
||||||
foreach (var p in instagramObservableParams)
|
|
||||||
AddOrSet(telegramUserId, p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
81
UsersData.cs
Normal file
81
UsersData.cs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
namespace InstaFollowersOverseer;
|
||||||
|
|
||||||
|
public class UsersData : DtsodFile
|
||||||
|
{
|
||||||
|
private Dictionary<string, List<InstagramObservableParams>> usersData=new();
|
||||||
|
|
||||||
|
public UsersData(string fileName) : base(fileName) {}
|
||||||
|
|
||||||
|
public override void LoadFromFile()
|
||||||
|
{
|
||||||
|
var dtsod=ReadDtsodFromFile(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var uset in dtsod)
|
||||||
|
{
|
||||||
|
string telegramUserId = uset.Key;
|
||||||
|
|
||||||
|
List<InstagramObservableParams> oparams = new();
|
||||||
|
foreach (DtsodV23 _overseeParams in uset.Value)
|
||||||
|
oparams.Add(new InstagramObservableParams(_overseeParams));
|
||||||
|
|
||||||
|
usersData.Add(telegramUserId, oparams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception($"your {FileName} format is invalid\n"
|
||||||
|
+ $"See {FileExampleName}", innerException: ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DtsodV23 ToDtsod()
|
||||||
|
{
|
||||||
|
var b = new DtsodV23();
|
||||||
|
foreach (var userS in usersData)
|
||||||
|
b.Add(userS.Key,
|
||||||
|
userS.Value.Select<InstagramObservableParams, DtsodV23>(iop =>
|
||||||
|
iop.ToDtsod()
|
||||||
|
).ToList());
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<InstagramObservableParams> Get(string telegramUserId)
|
||||||
|
{
|
||||||
|
if (!usersData.TryGetValue(telegramUserId, out var overseeParams))
|
||||||
|
throw new Exception($"there is no settings for user {telegramUserId}");
|
||||||
|
return overseeParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddOrSet(string telegramUserId, InstagramObservableParams instagramObservableParams)
|
||||||
|
{
|
||||||
|
// Add
|
||||||
|
// doesnt contain settings for telegramUserId
|
||||||
|
if (!usersData.TryGetValue(telegramUserId, out var thisUsersData))
|
||||||
|
{
|
||||||
|
usersData.Add(telegramUserId, new (){ instagramObservableParams });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set
|
||||||
|
// settings for telegramUserId contain InstagramObservableParams with instagramObservableParams.instagramUserId
|
||||||
|
for (var i = 0; i < thisUsersData.Count; i++)
|
||||||
|
{
|
||||||
|
if (thisUsersData[i].instagramUserId == instagramObservableParams.instagramUserId)
|
||||||
|
{
|
||||||
|
thisUsersData[i] = instagramObservableParams;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add
|
||||||
|
// doesnt contain InstagramObservableParams with instagramObservableParams.instagramUserId
|
||||||
|
thisUsersData.Add(instagramObservableParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddOrSet(string telegramUserId, IEnumerable<InstagramObservableParams> instagramObservableParams)
|
||||||
|
{
|
||||||
|
foreach (var p in instagramObservableParams)
|
||||||
|
AddOrSet(telegramUserId, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user