В 2020ом мы пользуемся разными музыкальными сервисами, но как реликт ушедшей эпохи, в забытом профиле ВК, у многих хранится музыка. Функции для загрузки нет, но что если позарез нужно спасти аудиозапись?
Поскольку такого софта в открытом доступе не обнаружилось, кроме парочки веб-сервисов требующих авторизацию через ВК (что не очень то и безопасно), под катом мы рассмотрим процесс создания self-hosted утилиты на современном C# для загрузки своих аудио, не сливающей данные профиля сторонним сервисам.
Одной из ценностей работы программиста является простота и по возможности лаконичность кода. Поэтому мы склеим несколько уже существующих библиотек чтобы получить нужное решение.
Работать утилита будет так:
dotnet vkm [login] [password] [audio-lemma]
Перво-наперво создадим репозиторий и опишем в одном файле csproj зависимости проекта
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!--Утилита будет работать из консоли-->
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<!--Строго запрещаем null на этапе компиляции, чтобы застраховаться от NRE -->
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<!--И включаем C# 9 который понадобится нам для top-level точки входа -->
<LangVersion>9</LangVersion>
</PropertyGroup>
<ItemGroup>
<!--Зависимость от VK API без необходимости вручную получать токен-->
<PackageReference Include="VkNet" Version="1.56.0" />
<!--Доступ к своим сообщениям, комментариям и музыке-->
<PackageReference Include="VkNet.AudioBypassService" Version="1.7.0" />
</ItemGroup>
</Project>
После этого с чистой совестью можно приступать к написанию кода. Нам потребуется авторизация утилиты в ВК с полным доступом к своему профилю. И как мы видим, благодаря экосистеме .NET, сделать это невероятно просто:
static class Vk
{
internal static VkApi LoginToVkApi(string login, string password)
{
// Включаем доступ к своим сообщениям, комментариям и аудиозаписям
var api = new VkApi(new ServiceCollection().AddAudioBypass());
api.Authorize(new ApiAuthParams
{
ApplicationId = 1980660,
Login = login,
Password = password,
Settings = All
});
$"Login as vk.com/id{api.UserId}".Println(DarkBlue);
return api;
}
}
Опишем точку входа и фильтр загружаемых аудиозаписей. Используем для этого top-level programs и прямо в файле Application.cs валидируем аргументы, одновременно инициализируя api
var vk = args.Length switch
{
3 => LoginToVkApi(args[0], args[1]),
_ => throw new ArgumentException("Invalid arguments. Usage:\n" +
" dotnet vkm [login] [password] [audio]\n" +
)
};
Приводим лемму для поиска аудиозаписи к upper-case
var lemma = args.Last().ToUpperInvariant();
И грепаем с помощью Linq все аудиозаписи с её вхождением. Отдельное спасибо хабраюзеру SuperHackerVk за способ получения mp3-ссылки регуляркой.
var audios = vk.Audio.Get(new AudioGetParams { Count = 6000 })
.Where(x => x.Title.ToUpperInvariant().Contains(lemma))
.Select(x => (x.Title, Url: Regex.Replace(
x.Url.ToString(),
@"/[a-zA-Z\d]{6,}(/.*?[a-zA-Z\d]+?)/index.m3u8()",
@"$1$2.mp3"
)));
Наконец остается только загрузить свои найденные аудио:
using var http = new HttpClient();
foreach (var (title, url) in audios)
{
$"Downloading {title}...".Println(DarkBlue);
await WriteAllBytesAsync($"{title}.mp3", await http.GetByteArrayAsync(url));
}
Вот и все! Утилита написана и готова к использованию в личных целях. Заметно как C# с каждым годом все больше превращается в хороший мультитул, позволяющий решать любой спектр задач. Расширения синтаксических возможностей которые при анонсах кажутся загромождающими язык, на практике напротив, позволяют сократить код и сделать его простым и понятным.
Репозиторий на GitHub c небольшими дополнениями и документацией по запуску.
Всем удачного дня!
Matisumi
То есть вы просто показали как установить два пакета из нугет и воспользоваться парой их функций?
beskaravaev
Ну что вы. Автор ещё включил Nullable ref types, которой ни разу не воспользовался. И если использовалась превью версия языка, то почему бы не воспользоваться превью .Net 5. Да, это в этом микро проекте ничего не даст, но раз уж автор начал.
Chronicler
Ограничения статической компиляции в любом случае лучше проставить заранее и не использовать, чем не проставить и получить NPE в рантайме.
beskaravaev
NRT в .Net не дают гарантий того, что вы не получите NRE (NPE в java и может ещё где), т.к.:
— анализатор не все ситуации может отработать корректно
— разработчик может подавить анализ использовав!
— разработчик библиотеки, которую вы используете не факт, что тоже включил их поддержку и не факт, что всё разметил правильно
В итоге у вас вагон и маленькая тележка способов обратиться по null. Включать фичу в таком мелком проекте имеет смысл только для того, чтобы потренироваться в её использовании, но мы не видим её применения НИ РАЗУ. А заострять на этом внимание в статье, если она не используется, вообще не имеет никакого смысла.
p.s. Я не против конкретно этой фичи, я даже за, но я против того, что автор указывает на фичу без её использования.
Chronicler
На этапе описания проекта автор подстраховался, вполне разумная практика по умолчанию, когда еще не знаешь сколько кода будет написано. Не вижу смысла придираться к ограничениям в плане безопасности.
Вы еще скажите что статическая компиляция в маленьких проектах лишняя и надо было сразу писать на JavaScript.
Chronicler
И какого использования NRT вы ожидали? Ошибок компиляции? Смысл ведь как раз в том чтобы изначально не давать программисту писать код использующий null. На мой взгляд не лишнее ограничение свободы.
Вы всерьез записали это в минусы NRT? Точно также происходит и в остальных языках с декларируемой null-safety (в Kotlin '!!' например). В этом и смысл, что использование null сразу будет заметно в коде.
beskaravaev
Это были не минусы NRT, это были аргументы к тому, что NRT не даёт 100% гарантии.
И да, это не является ограничением статической компиляции, это лишь анализ проекта с возможностью поднять предупреждения до уровня ошибк.
Reformat Автор
Аналогичной self-hosted утилиты нет в открытом доступе. Есть парочка веб-сервисов которые требуют входа через профиль ВК, что не очень то безопасно, а youtube-dl не умеет нормально выкачивать аудио из ВК. Поэтому статья описывает несуществующее доселе решение. Не в этом ли и заключается ценность софта?
Делать сложные вещи по возможности просто и лаконично одна из задач работы программиста. Или вы хотели полотнище кода для статьи на хабре?
yarkov
А в чём их небезопасность? Просят вводить логин/пасс? Тогда да, доверять не стоит. А если авторизация через приложение ВК, то что в этом такого?
Reformat Автор
Доступ к профилю автоматически дает сервису данные страницы, электронную почту, друзей, фотографиям. Не давая при этом логина и пароля.
Как-то не хочется чтобы эти данные собирались
yarkov
Ах перестаньте )) Эти данные давно собраны теми кому надо ) И без вашего согласия.
Chronicler
Вы хотите чтобы вдобавок к "кому надо", эти данные получил еще и какой нибудь сервис Васи Пупкина?)
ARad
Логин и пароль не дает доступ к этой и другой информации?