<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: EDEXADE</title>
    <description>The latest articles on DEV Community by EDEXADE (@edexade).</description>
    <link>https://dev.to/edexade</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1153935%2F6b83a8f6-3f0f-4bdc-9588-adf6dfeb6a7e.jpg</url>
      <title>DEV Community: EDEXADE</title>
      <link>https://dev.to/edexade</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/edexade"/>
    <language>en</language>
    <item>
      <title>Using the Actor System in ASP.NET</title>
      <dc:creator>EDEXADE</dc:creator>
      <pubDate>Fri, 19 Jul 2024 20:52:49 +0000</pubDate>
      <link>https://dev.to/edexade/using-the-actor-system-in-aspnet-481k</link>
      <guid>https://dev.to/edexade/using-the-actor-system-in-aspnet-481k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Recently, I completed the development of a chess application on the .NET platform using &lt;a href="https://en.wikipedia.org/wiki/Actor_model" rel="noopener noreferrer"&gt;Actors&lt;/a&gt; that utilizes modern approaches and technologies to ensure scalability and performance. In this post, I want to share key aspects of the architecture and technologies that helped me achieve this goal*.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;- concrete realization of any actor and all project you can see here:
&lt;a href="https://github.com/issamansur/ChessLibrary" rel="noopener noreferrer"&gt;https://github.com/issamansur/ChessLibrary&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Original state: &lt;a href="https://www.linkedin.com/pulse/building-scalable-chess-application-net-using-actors-model-mansur-yl7mc/?trackingId=PUJyTN9LT1y8c5GfNr97cg%3D%3D" rel="noopener noreferrer"&gt;https://www.linkedin.com/state&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Layered Architecture
&lt;/h2&gt;

&lt;p&gt;The application is built using a layered architecture, which allows for clear separation of responsibilities among different components and simplifies maintenance and development. The main layers include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Presentation Layer: ASP.NET controllers and views.&lt;/li&gt;
&lt;li&gt;Infrastructure Layer: Repositories, Entity Framework, PostgreSQL, actors.&lt;/li&gt;
&lt;li&gt;Application Layer: Service classes, CQRS (Command and Query), MediatR.&lt;/li&gt;
&lt;li&gt;Domain Layer: Domain entities and chess logic (my own library).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Technologies
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Akka.NET and Microsoft Orleans
To support multiple games concurrently, I used an actor system. Each actor manages the state of a single chess game. For implementing actors, I considered two options: Akka.NET and Microsoft Orleans.&lt;/li&gt;
&lt;li&gt;ASP.NET
ASP.NET is used for creating controllers and views, providing user interaction through a web interface.&lt;/li&gt;
&lt;li&gt;PostgreSQL and Entity Framework
For data storage, I chose PostgreSQL as the database and Entity Framework for database operations. This allows efficient data management and takes advantage of ORM.&lt;/li&gt;
&lt;li&gt;CQRS and MediatR
Using the CQRS (Command Query Responsibility Segregation) pattern allows separating read and write operations, simplifying maintenance and scalability. The MediatR library helps manage commands and queries, ensuring flexibility and extensibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common interface for Actor's Service
&lt;/h2&gt;

&lt;p&gt;First, it was necessary to create a common interface. Each of the services responsible for a particular implementation of the actor model needed to implement this interface. This way, we can switch between specific implementations by changing just one line of code.&lt;/p&gt;

&lt;p&gt;The main operations we needed were "Get game", "Join game," and "Make move." "Create game" is a fairly simple operation that doesn't require conditions, so it was decided to exclude it from the logic. Thus, we get the following interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// IChessActorService.cs
public interface IChessActorService
{
    Task&amp;lt;Game&amp;gt; GetGameAsync(GetGameQuery getGameQuery, CancellationToken cancellationToken);
    Task&amp;lt;Game&amp;gt; JoinGameAsync(JoinGameCommand joinGameCommand, CancellationToken cancellationToken);
    Task&amp;lt;Game&amp;gt; MoveGameAsync(MoveGameCommand moveGameCommand, CancellationToken cancellationToken);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to interface, we can easily switch between a specific implementation, determining the necessary one directly in the code or using "Configuration" for it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Akka.NET
&lt;/h2&gt;

&lt;p&gt;Akka.NET provides a powerful and flexible actor model that allows for the creation of lightweight actors. Each game is managed by a dedicated actor, which handles game state, player moves, and game logic. The actor model in Akka.NET is highly concurrent and resilient, making it an excellent choice for real-time applications like a chess game.&lt;/p&gt;

&lt;p&gt;Actors in Akka.NET communicate with each other asynchronously using message passing, which helps to avoid the complexities of multithreading and ensures that the application remains responsive even under heavy load. The actor hierarchy in Akka.NET also allows for easy supervision and fault tolerance, as parent actors can manage the lifecycle and error handling of their child actors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;As previously mentioned, Akka.NET offers a lower-level interface for implementing the actor model, which must be considered during development. For example, when creating any actor, it belongs to a specific parent. The parent, in turn, becomes responsible for the new actor, monitoring its state and reacting to various events, such as its unexpected termination.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpt8gdin7ymh64lljh68j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpt8gdin7ymh64lljh68j.png" alt="Top-level architecture (Part 1. Top-level Architecture)" width="528" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our case, we needed an actor for each game so that each game could be processed in parallel with others, increasing the speed of move and event handling. Returning to the architecture, we find that in addition to the game actors, we need a main actor that can route each request to the appropriate actor for the specific game. Looking ahead, there is no need for supervisors to monitor each actor externally. In this case, the logic of the parent actor suffices.&lt;/p&gt;

&lt;p&gt;Thus, the actor system will look as shown in the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzrkiay7dell9o86pk63m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzrkiay7dell9o86pk63m.png" alt="System of Actors for app" width="798" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Realize of service interface
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// AkkaNetSystem.cs
public class AkkaNetSystem: IChessActorService
{
    private readonly IServiceScopeFactory _scopeFactory;
    private IActorRef _chessMaster;

    public AkkaNetSystem(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
        var system = ActorSystem.Create("chess-system");
        _chessMaster = system.ActorOf(
            ChessMaster.Props(_scopeFactory), 
            "chess-master"
        );
    }

    public async Task&amp;lt;Game&amp;gt; GetGameAsync(
        GetGameQuery getGameQuery, 
        CancellationToken cancellationToken
    )
    {
        return await _chessMaster.Ask&amp;lt;Game&amp;gt;(
            message: getGameQuery, 
            timeout: TimeSpan.FromSeconds(3),
            cancellationToken: cancellationToken
        );
    }

    // Other methods with same realization
    …
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integrating with ASP.NET
&lt;/h3&gt;

&lt;p&gt;Given that actors run throughout the application's lifecycle in a single context, we register them as singletons. The service starts up perfectly, initializing the actor system. However, there is a nuance: during a "soft" shutdown, the service simply stops without gracefully shutting down the actors. Even if we override the Dispose method, issues with IServiceScopeFactory arise.&lt;/p&gt;

&lt;p&gt;Due to these problems, the correct solution was to use HostedService so that we could define events for starting and stopping the service. To do this, we update the AkkaNetSystem class by also inheriting from IHostedService and overriding the StartAsync() and StopAsync() methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// AkkaNetSystem.cs
public class AkkaNetSystem: IChessActorService, IHostedService
{
    …
    public AkkaNetSystem(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }
   public async Task StartAsync(CancellationToken cancellationToken)
    {
        var system = ActorSystem.Create("chess-system");
        _chessMaster = system.ActorOf(
            ChessMaster.Props(_scopeFactory), 
            "chess-master"
        );
        await Task.CompletedTask;
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        await _chessMaster.GracefulStop(TimeSpan.FromSeconds(3));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, register the service as IHostedService:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// DependencyInjection.cs
…
public static class DependencyInjection
{
   private static void AddActorAkkaNet(this IServiceCollection services)
    {
        services.AddSingleton&amp;lt;IChessActorService, Actors.AkkaNet.AkkaNetSystem&amp;gt;();
        // starts the IHostedService, which creates the ActorSystem and actors
        services.AddHostedService&amp;lt;Actors.AkkaNet.AkkaNetSystem&amp;gt;(
            sp =&amp;gt; (Actors.AkkaNet.AkkaNetSystem)sp.GetRequiredService&amp;lt;IChessActorService&amp;gt;()
        );
    }
    …
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Microsoft Orleans
&lt;/h2&gt;

&lt;p&gt;Orleans invented an abstraction called a virtual actor, where actors exist all the time. In this case, an actor, when used by a client, is not explicitly created or destroyed, and it is not affected by failures. This is why they are always accessible.&lt;/p&gt;

&lt;p&gt;In this regard, the Orleans programming model reduces the complexity inherent in highly parallel distributed applications without limiting capabilities or imposing restrictions on the developer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;The actor model implementation in Microsoft Orleans differs from the system previously discussed in Akka.NET. To understand how to organize your system using Orleans, it's essential to grasp what Grain, Silo, and Cluster mean.&lt;/p&gt;

&lt;p&gt;Grain is one of several primitives in Orleans. From an actor model perspective, grains are virtual subjects. The primary standard unit in any Orleans application is a grain. Grains are entities composed of user-defined credentials, behaviors, and state. Let's consider the following visual representation of a grain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rgwqhru5wbbo54tawt7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rgwqhru5wbbo54tawt7.png" alt="Visual performing of Grain" width="744" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Orleans, we only need one type of grain to represent the game. This single grain will denote the entire game, and we will interact with it within the cluster through silos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Realize of service interface
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// MicrosoftOrleansSystem.cs
…
public class MicrosoftOrleansSystem: IChessActorService 
{
    IGrainFactory GrainFactory { get; init; }

    public MicrosoftOrleansSystem(IGrainFactory grainFactory)
    {
        GrainFactory = grainFactory;
    }

    public async Task&amp;lt;Game&amp;gt; GetGameAsync(GetGameQuery getGameQuery, CancellationToken cancellationToken)
    {
        IGameMasterGrain gameMaster = GrainFactory.GetGrain&amp;lt;IGameMasterGrain&amp;gt;(getGameQuery.GameId);
        return await gameMaster.GetGameAsync(cancellationToken);
    }

    //
    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integrating with ASP.NET
&lt;/h3&gt;

&lt;p&gt;Unlike Akka.NET, we don't need to connect the service as an IHostedService because Orleans handles this himself. However, to make this work, we need to use the special "UseOrleans()" method extension for the HostBuilder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// DependencyInjection.cs (doesn't working without serialization for Game)
…
   private static void AddActorMicrosoftOrleans(this IServiceCollection services, IHostBuilder hostBuilder)
    {
        hostBuilder.UseOrleans(siloBuilder =&amp;gt;
        {
            siloBuilder
                .UseLocalhostClustering();
        });

        services.AddSingleton&amp;lt;IChessActorService, Actors.MicrosoftOrleans.MicrosoftOrleansSystem&amp;gt;();
    }
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When attempting to start the server, however, we may encounter a data serialization error. This is because when deploying to the cloud or different machines, issues may arise with our Game class returned by the grain in each method call. To address this, we also need to add a serializer. "JsonSerializer" is well-suited for this task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// DependencyInjection.cs (working without serialization for Game)
…
       hostBuilder.UseOrleans(siloBuilder =&amp;gt;
        {
            services.AddSerializer(
                serializerBuilder =&amp;gt;
                {
                    serializerBuilder.AddJsonSerializer(_ =&amp;gt; true);
                }
            );
            siloBuilder
                .UseLocalhostClustering();
        });
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Performance test
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35mha4syw2fmyxptr5qc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35mha4syw2fmyxptr5qc.png" alt="200 users (100 games), 10 minutes. Akka.NET vs Orleans" width="744" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This architecture and set of technologies enable supporting multiple chess games concurrently with high performance and scalability. The application of CQRS and MediatR simplifies managing commands and queries, while the use of an actor system ensures efficient state management.&lt;/p&gt;

&lt;p&gt;I hope my experience will be useful to those considering building complex applications on the .NET platform, or for those just starting to explore its use. If you have any questions or want to discuss details, feel free to leave comments!&lt;/p&gt;

</description>
      <category>asp</category>
      <category>architecture</category>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Музыкальный discord бот Kai'Sa</title>
      <dc:creator>EDEXADE</dc:creator>
      <pubDate>Thu, 14 Sep 2023 09:35:57 +0000</pubDate>
      <link>https://dev.to/edexade/muzykalnyi-discord-bot-kaisa-1p24</link>
      <guid>https://dev.to/edexade/muzykalnyi-discord-bot-kaisa-1p24</guid>
      <description>&lt;h2&gt;
  
  
  🎵 Добро пожаловать в мир музыки с "Кайсой из К/DA"! 🎵
&lt;/h2&gt;

&lt;p&gt;🎧 Познакомьтесь с вашим новым музыкальным спутником, который перенесет вас в мир магии и музыки, как это делают Кайсы из K/DA! Наш бот - это не просто музыкальный бот, это настоящий артист, создающий уникальную атмосферу на вашем сервере Discord.&lt;/p&gt;

&lt;p&gt;✨ Почему выбрать именно нас:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Поддержка всех ВК песен, альбомов и плейлистов&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;🎶 Бескрайний музыкальный опыт: Наш бот предоставляет доступ к миллионам треков самых разных жанров. От хип-хопа до классики, от K-Pop до рок-н-ролла - у нас есть всё!&lt;/li&gt;
&lt;li&gt;🤖 Интуитивный интерфейс управления: Наш бот прост в использовании, даже если вы новичок в Discord. Управление музыкой - это легко!&lt;/li&gt;
&lt;li&gt;🌟 Поддержка текстовых и голосовых команд: Вы можете управлять музыкой, даже не выходя из голосового чата!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎉 Присоединяйтесь к нам и окунитесь в мир музыки и развлечений, напоминающий невероятные выступления Кайсы из K/DA на большой сцене! Наслаждайтесь звуками и создавайте незабываемые моменты на своем сервере Discord с музыкальным ботом "Кайса из К/DA"! 🎶💃🎤&lt;/p&gt;

&lt;h2&gt;
  
  
  Не терпится начать?)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Дискорд:
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://discord.com/oauth2/authorize?client_id=1147834135918956577&amp;amp;permissions=0&amp;amp;scope=bot%20applications.commands"&gt;&lt;u&gt;Нажмите, чтобы добавить бота к себе на сервер&lt;/u&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  GitHub:
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/issamansur/KaiSa"&gt;&lt;u&gt;Нажмите, чтобы посмотреть начинку и сказать, что это &lt;del&gt;говнокод&lt;/del&gt;&lt;/u&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;h2&gt;
  
  
  Команды
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ - готово&lt;/li&gt;
&lt;li&gt;⌛ - в процессе&lt;/li&gt;
&lt;li&gt;❌ - в планах&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;b&gt;Команды управления ботом&lt;/b&gt;&lt;/td&gt;
    &lt;td&gt;&lt;b&gt;Команды управления аккаунтом пользователя&lt;/b&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;✅ /ping&lt;/td&gt;
    &lt;td&gt;✅ /register&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;⌛ /help&lt;/td&gt;
    &lt;td&gt;✅ /unregister&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;✅ /report&lt;/td&gt;
    &lt;td&gt;✅ /auth [id гильдии] [логин/телефон] [пароль]&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;b&gt;Команды поиска и воспроизведения музыки&lt;/b&gt;&lt;/td&gt;
    &lt;td&gt;&lt;b&gt;Команды управления воспроизведением музыки&lt;/b&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;✅ /search [название/автор песни]&lt;/td&gt;
    &lt;td&gt;✅ /list&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;✅ /search-album [название плейлиста (исполнителя)]&lt;/td&gt;
    &lt;td&gt;✅ /repeat [OFF | ONE | ALL]&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;✅ /search-playlist [название плейлиста (пользователя)]&lt;/td&gt;
    &lt;td&gt;✅ /skip&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;⌛ Soon...&lt;/td&gt;
    &lt;td&gt;✅ /quit&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Что мы кокодили, кокожим и будем кокодить:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Общее:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Воспроизведение и интерактивность с голосовыми каналами&lt;/li&gt;
&lt;li&gt;✅ Интеграция &lt;code&gt;vkpymusic&lt;/code&gt; для доступа к аудио и плейлистам&lt;/li&gt;
&lt;li&gt;✅ Работа с аудио&lt;/li&gt;
&lt;li&gt;✅ СКАЧИВАНИЕ!!!&lt;/li&gt;
&lt;li&gt;✅ Работа с плейлистами&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Очередь треков:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Своя очередь для каждой группы&lt;/li&gt;
&lt;li&gt;✅ Очередь треков (синхронная)&lt;/li&gt;
&lt;li&gt;❌ Очередь асинхронная (с использованием &lt;code&gt;asyncio.Queue&lt;/code&gt; или иначе)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Токены VK API:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Сохранение &lt;code&gt;API&lt;/code&gt; токенов для каждой гильдии/сервера&lt;/li&gt;
&lt;li&gt;✅ Автоматическое переподключение сервиса вместо &lt;code&gt;/register&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;❌ Проверка валидности &lt;code&gt;API&lt;/code&gt; токена&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Прочее:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;⌛ Редизайн и правки&lt;/li&gt;
&lt;li&gt;⌛ Документация и комментарии к коду&lt;/li&gt;
&lt;li&gt;⌛ Тестирование и отладка&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Возможное и невозможное:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;❌ Дополнительные функции для управления плейлистами&lt;/li&gt;
&lt;li&gt;❌ Интеграция с другими музыкальными сервисами&lt;/li&gt;
&lt;li&gt;❌ Работоспособность на 100%&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discord</category>
      <category>bot</category>
      <category>music</category>
      <category>python</category>
    </item>
    <item>
      <title>VKpyMusic - your tool for audio VK API</title>
      <dc:creator>EDEXADE</dc:creator>
      <pubDate>Tue, 05 Sep 2023 11:06:31 +0000</pubDate>
      <link>https://dev.to/edexade/vkpymusic-your-tool-for-audio-vk-api-526</link>
      <guid>https://dev.to/edexade/vkpymusic-your-tool-for-audio-vk-api-526</guid>
      <description>&lt;p&gt;🎵 Introducing VKPymusic: Your Ultimate Music API for Python 🚀&lt;/p&gt;

&lt;p&gt;Hey there, fellow developers! We're excited to introduce you to VKPymusic, the ultimate music API for Python enthusiasts and music aficionados alike. 🎶&lt;/p&gt;

&lt;p&gt;📦 &lt;strong&gt;What is VKPymusic?&lt;/strong&gt;&lt;br&gt;
VKPymusic is a powerful Python library that provides seamless access to the VKontakte (VK) music ecosystem. With VKPymusic, you can effortlessly search for music, create playlists, retrieve audio tracks, and much more, all through the VK API.&lt;/p&gt;

&lt;p&gt;🚀 &lt;strong&gt;What's New?&lt;/strong&gt;&lt;br&gt;
We've been hard at work, and we're thrilled to share the latest updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✨ &lt;strong&gt;Playlist Support:&lt;/strong&gt; Now you can search for, retrieve, and manipulate audio tracks within playlists.&lt;/li&gt;
&lt;li&gt;📝 &lt;strong&gt;Logging Integration:&lt;/strong&gt; We've improved code structure, variable/function names, and enhanced error handling, including the deletion of credentials in ANY situation.&lt;/li&gt;
&lt;li&gt;🚧 &lt;strong&gt;Code Enhancements:&lt;/strong&gt; A revamped structure and naming conventions for a smoother development experience.&lt;/li&gt;
&lt;li&gt;🔑 &lt;strong&gt;Token Management:&lt;/strong&gt; &lt;code&gt;get_token()&lt;/code&gt; now returns the token as a string, and &lt;code&gt;save_to_config()&lt;/code&gt; accepts a filename argument for config storage.&lt;/li&gt;
&lt;li&gt;⚙️ &lt;strong&gt;Enhanced Auth Handling:&lt;/strong&gt; Our &lt;code&gt;auth()&lt;/code&gt; method now includes 4 NEW handlers for various scenarios.&lt;/li&gt;
&lt;li&gt;🔄 &lt;strong&gt;Async Awesomeness:&lt;/strong&gt; Introducing &lt;code&gt;TokenReceiverAsync&lt;/code&gt; for async auth with async handlers.&lt;/li&gt;
&lt;li&gt;🐞 &lt;strong&gt;Bug Squashing:&lt;/strong&gt; We've fixed various bugs and potential errors for a smoother user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📣 &lt;strong&gt;We Want Your Input!&lt;/strong&gt;&lt;br&gt;
But that's not all! We're eager to hear from you. We welcome your advice, recommendations, and even constructive criticism. Are there specific features you'd like to see? Any challenges you've encountered during implementation? Your feedback will help shape the future of VKPymusic!&lt;/p&gt;

&lt;p&gt;🚀 &lt;strong&gt;Get Started&lt;/strong&gt;&lt;br&gt;
Ready to dive in? Explore VKPymusic on GitHub: &lt;a href="https://github.com/issamansur/vkpymusic"&gt;VKPymusic GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎉 My First Post!&lt;br&gt;
This is my first post on dev.to, and I couldn't be more thrilled to be part of this amazing community. Stay tuned for more updates, tutorials, and insights on VKPymusic right here on dev.to. Let's make VKPymusic the go-to library for all your VK music needs!&lt;/p&gt;

&lt;p&gt;Stay tuned for more updates, tutorials, and insights on VKPymusic right here on dev.to. Let's make VKPymusic the go-to library for all your VK music needs! 🎉&lt;/p&gt;

&lt;p&gt;Follow us for the latest news, and feel free to reach out with your thoughts. Together, we'll rock the Python music world!&lt;/p&gt;

&lt;h1&gt;
  
  
  OpenSource #MusicAPI #VKPymusic #Python #DevTo #DeveloperLife
&lt;/h1&gt;

</description>
      <category>vk</category>
      <category>api</category>
      <category>music</category>
      <category>python</category>
    </item>
  </channel>
</rss>
