Блог о Gentoo и около-линуксовым штукам

13 июня 2018 г.

Заметка по настройке exim4 на работу с Gmail @ Debian

2:21 Опубликовал Дмитрий Исаенко , Нет комментариев
При сбоях в работе демонов часто внутри них есть возможность слать письма. Мне бы хотелось бы получать отчёты на почту в случае чего-то непредвиденного. Раньше я пользовался ssmtp и он действительно хорош для embedded-систем, но Debian советует использовать exim4. Ну что же, я его попробовал и он действительно хорош. 
Ниже краткая заметка (конспект с материалов сайта wiki Debian, см.в конце) как быстро прикрутить зарегестрированный адрес в gmail для передачи сообщений в мир.

Для начала ставим exim4:
# aptitude install exim4-daemon-light exim4-config
Настраиваем exim4:
# dpkg-reconfigure exim4-config
1. Общий тип почтовой конфигурации: «отправка почты через smarthost; приём по SMTP или через fetchmail»
2. Почтовое имя системы: «localhost»
3. IP-адреса, с которых следует ожидать входящие соединения SMTP: «127.0.0.1»
4.Другие места назначения, для которых должна приниматься почта: оставить пустым
5. Машины, для которых доступна релейная передача почты:
 оставить пустым
6. IP-адрес или имя хоста являющегося исходящим smarthost: «smtp.gmail.com::587»
7. Скрывать локальное почтовое имя в исходящей почте? НЕТ
8. Сокращать количество DNS-запросов до минимума (дозвон по требованию)? НЕТ
9. Метод доставки локальной почты: mbox формат в /var/mail/
10. Разделить конфигурацию на маленькие файлы? ДА (или НЕТ)
Редактируем пароль для аккаунта в gmail
# vim /etc/exim4/passwd.client
 *.google.com:имя_пользователя_gmail@gmail.com:y0uRpaSsw0RD

Добавим правило для перезаписи имени отправителя (/etc/email-addresses ):
(В данный момент это не требуется, но мейнтейнеры exim говорят, что будет не лишним.)
# echo 'локальное_имя_пользователя: имя_пользователя_gmail@gmail.com' >> /etc/email-addresses
# echo 'локальное_имя_пользователя@localhost: имя_пользователя_gmail@gmail.com' >> /etc/email-addresses
# echo 'локальное_имя_пользователя@hostname1: имя_пользователя_gmail@gmail.com' >> /etc/email-addresses
# echo 'локальное_имя_пользователя@hostname1.localdomain: имя_пользователя_gmail@gmail.com' >> /etc/email-addresses
Применяем изменения:
# update-exim4.conf
# invoke-rc.d exim4 restart
# exim4 -qff
Говорим что вся почта, которую система будет генерировать и пытаться отправить root должна посылаться на адрес gmail (например на тот же, с которого происходит отправка. Или другой.):
vim /etc/aliases
root: имя_пользователя_gmail@gmail.com
Протестируем:
echo "Мудрое сообщение"|mail -s 'Значимый заголовок' root
Также может понадобиться разрешить gmail работу с непроверенными источниками. Это та фича, которая при попытке привязать новый почтовый клиент спрашивает разрешения. При её отключении спрашивать перестанет.

Всё. Проще чем казалось :)

Ссылки:
https://wiki.debian.org/GmailAndExim4

10 апреля 2018 г.

NoWOL: питание ПК через интернет. Часть 2.

5:55 Опубликовал Дмитрий Исаенко , , Нет комментариев
Продолжаем! Для проекта NoWOL есть Android-приложение с виджетом.

Вообще, там всё весьма просто. Как будет возможность (не лень), загружу исходники в GitHub. Пока же там лежит вполне готовая к использованию APK'шка.
Из ключевых моментов: внутри используется библиотека Volley; работает приложение под Android 4.0 и выше (minSdkVersion 14, target 26).

Архитектура проста донельзя. Приложение отправляет HTTP-запросы по указанному адресу и парсит ответы.

А теперь скриншоты!

После установки станет доступно основное приложение, а в разделе виджетов появится новый виджет с одноимённым названием «NoWOL».

Что касается приложения, то в нём доступно несколько состояний: неизвестно, онлайн, офлайн, нет ответа (от хоста). Обновить состояние можно нажав на кнопочку в верхней панели.


Если нажать на шестерёнку на верхней панели, всплывёт окно для указания IP хоста в сети. Следует обратить внимание на формат записи. Защиты от дурака там, к сожалению, не так много как хотелось бы. Вот хороший пример:

  

При добавлении виджета появится окно конфигуратора. Как видно, в нём нет указателя на адрес хоста. Он настраивается внутри приложения, поэтому сперва стоит запустить его.
Зато в конфигураторе можно выбрать задний фон (белый или чёрный) с альфа-каналом и уровень его прозрачности.
UI немного неочевиден и меняется в зависимости от выбора "галочки". Я знаю, так делать нехорошо.
 

В итоге, после добавления, виджет будет выглядеть как-то так (см. ниже). В его верхней строке может отображаться один из трёх возможных статусов. В отличии от приложения, там нет варианта "неизвестно". Зато вдалеке от домашней сети будет красоваться "нет ответа".

Забавный момент: если ПК в режиме ожидания, то статус будет или "онлайн" или "офлайн" в зависимости от того, мигнула ли лампочка в момент запроса состояния :)

Принудительно обновить статус можно ловко попав по верхнему правому углу, или через приложение — оно передаст полученные данные в виджет. 
Вообще, статус обновляется сам каждые пол часа (если мне не изменяет память, но уж точно не чаще). Сделано это только для того, чтобы не сажать батарею телефона почём зря.


В общем-то на этом всё. Надеюсь, вам понравилось =)

NoWOL: питание ПК через интернет. Часть 1.

4:28 Опубликовал Дмитрий Исаенко , , , Нет комментариев
Ох, давно хотел уже задокументировать это здесь, да всё времени не было. И вот, спустя полтора года…

Какую проблему решаем?

Стоит задача включать и выключать ПК нажимая на кнопки включения\выключения и сброса не руками, а через интернет (ну или через тоннель в интранет). В идеале спросонья через виджет в телефоне а-ля узнал погоду за бортом, включил ПК и можно идти ставить кофе.

Для этого было решено пилить какой-то контроллер Atmega с каким-то ethernet-свистком, чтобы он через оптопары замыкал кнопки включения. А заодно сообщал об успехе или неуспехе затеи.

Немного покопавшись я решил закупить основанную на enc28j60 приблуду для ардуины, а заодно и саму ардуину. Изучив особенности программирования enc28j60 руками (без высокоуровневых IDE и готовых библиотек) и бегло осмотрев errata, который, надо отметить, чуть ли не больше даташита, стало ясно, что на низком уровне рулить “этим” сущий ад и боль. Поэтому, будем собирать всё на базе добротного китайского клона Arduino nano или функционального аналога (лучше просто взять arduino, правда).

В итоге система будет состоять из основного модуля в виде связки Arduino+enc28j60 и выносного блока с оптопарами и резисторами.

В целом выглядеть и подключаться всё будет так:

Но перед тем, как начать…

Поставим себе пару пакетов:
1. dev-embedded/arduino
2. sci-electronics/eagle (ветка 7.x.x и лучше из нестабильной ветки) 
Все необходимые файлы лежат в проекте на GitHub:
https://github.com/developersu/NoWOL

Про выносной модуль

Файлы для Eagle CAD находятся в директории eagle_files/m2Board/ .
Необходимые библиотеки в eagle_files/lib/ .

Для выносного модуля понадобится:

Part Value Device Package Library Sheet
IC2 КР293КП4А DIL08 ic-package 1
IC3 КР293КП4А DIL08 ic-package 1
IN PINHD-1X6 1X06 pinhead 1
OUT PINHD-1X6 1X06 pinhead 1
R1 450Ω или 470Ω R-EU_0204/5 0204/5 resistor 1
R2 450Ω или 470Ω R-EU_0204/5 0204/5 resistor 1
R3 330Ω R-EU_0204/5 0204/5 resistor 1
TO_MCU PINHD-1X5 1X05 pinhead 1

По-поводу R1 и R2 резисторов, я собрал две пары, чтобы получилось 450 Ом в каждой. Думаю, что если взять просто пару штук на 470 Ом всё тоже будет работать. Но всё же обещать не буду.

Его принципиальная схема выглядит весьма просто:

Разводка выполняется на односторонней плате:


* 'cuz soviet works better
Если присмотреться, разводка слегка отличается от той, что приведена на первом рисунке. Тут я убрал перемычку.

Как вы уже поняли, в качестве оптопар используется отечественная схема КР293КП4А в корпусе DIP8. Внутри каждой микросхемы находится 2 оптопары. Одна из схем замыкает и размыкает кнопки (питание и сброс), а вторая говорит микроконтроллеру включена ли система, определяя это по светодиоду-индикатору питания. Если первую микросхему замыкает МК, то вторую — ПК. Через отдельный пин микроконтроллер зажигает индикатор питания сам, когда понимает, что и система (ПК) тоже его зажгла. Уж не знаю.. может это несколько избыточно и можно было сделать проще. Впрочем, получилось как получилось.

Примечание: наверное надо было навесить на вторую оптопару какие-то резисторы.. но блин, datasheet по ним такой немногословный. В общем как-то работает уже больше года, так что, пока всё не сгорело, имеет право на жизнь.

Если всё спаять и приправить должным количеством пыли, получится примерно следующее:


Про программирование Arduino

Теперь перейдём к программированию Arduino. Как говорилось ранее, предполагается использование Arduino Nano.
Я уже не помню что куда нажимать и подключать, чтобы это дело прошить но у меня есть скетч!
Для этого скетча понадобится библиотека ehtercard. И скетч и библиотека находятся в директории arduino_sketchbook/.

А вот и сам код:
#include <EtherCard.h>

#define PWR_PIN 6
#define RST_PIN 7
#define PWR_LED_IN 8
#define PWR_LED_OUT 5


int i;
// Зададим MAC адрес устройства
static byte mymac[] = { 0xDE,0xAD,0xBE,0xEE,0xEE,0xEF };
 
// Чем больше данных отображается на странице, тем больше требуется буфер для них
byte Ethernet::buffer[900];
BufferFiller bfill;
 
//Массив задействованных контактов для управления оптопарами
int LedPins[] = {PWR_PIN,RST_PIN};
 
//Массив для фиксации изменений
boolean PinUpdate = 0;      //100-reset 200-power 5050-powerOFF
 
const char http_OK[] PROGMEM =
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"Pragma: no-cache\r\n\r\n"
"\r\n"
"<html>"
  "<head><title>"
    "noWOL"
  "</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><style>"
  "body { font-family: monospace;\n"
   "background-color: #000000;\n"
   "font-size: 30px;\n"
   "font-weight: bold;\n"
   "color: #b2b2b2;}\n"
   "a:link, a:visited {  display: inline-block;\n"
  "color: #b2b2b2;\n"
  "font-weight: 700;\n"
  "text-decoration: none;\n"
  "padding: .3em 2em;\n"
  "outline: none;\n"
  "border: 2px solid;\n"
  "border-radius: 15px;\n"
  "transition: 0.2s;}\n"
  "a:hover {color: #fefefe;}\n"
  "</style></head>"
  "<body><center>"
;
const char http_Found[] PROGMEM =
"HTTP/1.0 302 Found\r\n"
"Location: /\r\n\r\n";

const char http_Unauthorized[] PROGMEM =
"HTTP/1.0 401 Unauthorized\r\n"
"Content-Type: text/html\r\n\r\n"
"401 Unauthorized";
 
void homePage()
{
bfill.emit_p(PSTR("$F"
  " "
  "$F<p>"
  "<a href='?RESET=on'>  RESET   </a><p>"  //D6
  "<a href='?POWER0=on'>  POWER   </a><p>" //D7 short
  "<a href='?POWER1=on'>POWER 5sec</a><br />"),  //D7 long
  //"PWR LED out D5 : $F <br /></body></html>"),
  
  http_OK,
  (digitalRead(PWR_LED_IN) == HIGH)?PSTR("<span style=\"color: #AA0000\">          ▄▄▄▄▄▄</span>"):PSTR("<span style=\"color: #00c600\">          ▄▄▄▄▄▄</span>")),//⬤
//  (bitRead(PORTD,PWR_LED_OUT) == HIGH)?PSTR("HIGH"):PSTR("LOW")),

"</center></body>"
"</html>"
  ;
}

void pick_pin(int pin, int del) {
      digitalWrite(pin,HIGH);
        delay(del);
        digitalWrite(pin,LOW);
        PinUpdate = 0;
}
 
void setup()
{
// SET UART
//  Serial.begin(9600);
//Change default ethercard CS - pin 8 to 10
  //if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0)

//  Serial.println( "Access to Ethernet controller failed");
    ether.begin(sizeof Ethernet::buffer, mymac, 10);
    ether.dhcpSetup();
//  if (!ether.dhcpSetup())
//       Serial.println("DHCP routine failed");
    //Print over UART configuration recieved:
//  ether.printIp("IP:  ", ether.myip);          
//  ether.printIp("GW:  ", ether.gwip);  
//  ether.printIp("DNS: ", ether.dnsip);  

  for(i = 0; i < 2; i++) {
    pinMode(LedPins[i],OUTPUT);
  }
  
    pinMode(PWR_LED_OUT,OUTPUT);
    pinMode(PWR_LED_IN,INPUT_PULLUP); // LED-питания как вход
}
 
void loop()
{
    delay(1);

        if (digitalRead(PWR_LED_IN) == HIGH) {        // если мать выключена
            if (bitRead(PORTD,PWR_LED_OUT) == HIGH) digitalWrite(PWR_LED_OUT,LOW);
        }
        else if (bitRead(PORTD,PWR_LED_OUT) == LOW) {
          digitalWrite(PWR_LED_OUT,HIGH);
        }

        switch (PinUpdate) {
          case 0:
            break;
          case 1:
            pick_pin(RST_PIN, 200);
            break;
          case 2:
            pick_pin(PWR_PIN, 200);
            break;
          case 3:
            pick_pin(PWR_PIN, 5050);
            break;
        }

    word len = ether.packetReceive(); //Проверить ethernet пакеты
    word pos = ether.packetLoop(len); //Проверить TCP пакеты
    if (pos) {
        bfill = ether.tcpOffset();
        char *data = (char *) Ethernet::buffer + pos;
        if (strncmp("GET /", data, 5) != 0) {
            bfill.emit_p(http_Unauthorized);
        }
        else {
            data += 5;
            if (data[0] == ' ') {
                    homePage(); //Если обнаружено изменения на станице, то запускаем функцию
            }
            //"10" = количество символов "?RESET=on ".
            else if (strncmp("?RESET=on ", data, 10) == 0) {
                bfill.emit_p(http_Found);
                                PinUpdate = 1;
            }
 
            else if (strncmp("?POWER0=on ", data, 11) == 0) {
                  bfill.emit_p(http_Found);
                                PinUpdate = 2;
            }
 
            else if (strncmp("?POWER1=on ", data, 11) == 0) {
                    bfill.emit_p(http_Found);
                                PinUpdate = 3;
            }

            else {
                //Страница не найдена
                bfill.emit_p(http_Unauthorized);
            }
        }
        ether.httpServerReply(bfill.position());
    }
}
Теперь, когда всё что надо прошито, соединяем как указано на рисунке в начале публикации и подключаем это дело к сети. На машрутизаторе должен быть настроен DHCP сервер.
Мак-адрес нового устройства, как ясно из исходного кода, будет de:ad:be:ee:ee:ef. Лучше сразу назначить постоянную аренду. В OpenWRT с LuCI идём в:
«Сеть» → «DHCP и DNS» → вкладка «Основные настройки» → «Постоянные аренды» → «Добавить».
Пишем там как показано на рисунке:


Когда всё настроено и подключено, заходим на адрес http://192.168.1.100 и видим следующее:


Только вот квадратик будет красным, а не зеленым. Это и есть индикатор питания.
Назначение кнопок пояснять нет смысла. Последняя симулирует долгое нажатие, что приводит к принудительному отключению.

То, что всё это находится в интрасети и не отсвечивает в мир меня вполне устраивает, ведь при подключении по VPN доступ появляется и в Android-приложении и через WEB-интерфейс. Ах да! Для всего этого дела есть ещё и Android-приложение :) Но о нём во второй части.

Вредные советы

Как бы не использовать Arduino?

Лучше таки его использовать.
Но можно и спаять свою ардуину, с блекджеком и профусетками, чтобы она была поменьше и конкретно под этот проект.
Сразу оговорюсь, я наделал кучу ошибок и паял отдельные костыли чтобы всё сошлось.. потом переделал схему, потом ещё пару раз, и уже не помню на сколько там правильная разводка. Так что лучше внимательно изучить и прислать мне фидбек в виде линки на исправленную версию. Или апробировать, если всё правильно =)

Используется двусторонний текстолит. Перемычки тут не помогут.

Находится всё в директории eagle_files/atmegaBoard/ .

Список компонентов:

Part Value Device Package Library Sheet
C1 22pF C-EUC0603 C0603 resistor 1
C2 22pF C-EUC0603 C0603 resistor 1
C3 10uF CC0603 C0603 eagle-ltspice 1
C4 22uF CC0603 C0603 eagle-ltspice 1
IC1 atmega328p atmega328p TQFP32-08 avr-6 1
IC3 LM1117IMPX-3.3 LM1117IMPX-3.3 SOT223 lm1117 1
JP1
PINHD-2X5 2X05 pinhead 1
JP3 PINHD-1X2 1X02 pinhead 1
Q1 16MHz XTAL/S QS special 1
SV1 MA05-1 MA05-1 con-lstb 1
U1 USB"" USB-MICRO-SMD MicroUSB 1

Схема принципиальная:


Сама разводка:


Что тут добавить.. земля на гребёнке справа. JP3 нужен для прошивки схемы. Прошивается она через Arduino IDE.. Кажется с помощью самой ардуины. Ну или через USBasp программатор. В общем, главное ничего не перепутать. А настройки должны быть вроде таких:

1)
 

2)


В следующей части будет обзор Android-приложения. APK файл находится в папке Android_APK.

Итого

У меня вся эта разработка шла не очень гладко, но получилось вполне сносно. Вот конечный результат в корпусе из спичек. Для антуража покрашено йодом.



Что касается дальнейшего развития этой инициативы, то я планирую добавить сюда ещё один выносной модуль для ещё одного ПК.

--
Особая благодарность Unyuu за неоценимый вклад. Во многом благодаря его советам этот проект стал возможен.


Лицензия Creative Commons
Текстовый материал распространяется по лицензии Creative Commons С указанием авторства-Некоммерческая-С сохранением условий 4.0 Всемирная.
Обратите внимание: это ограничение не касается графических изображений и исходного кода. Если на самом изображении не указано иного, они доступны по лицензии Creative Commons С указанием авторства 4.0 Всемирная.

22 марта 2018 г.

О ретрекерах rutracker @ OpenWRT

3:55 Опубликовал Дмитрий Исаенко Нет комментариев
В роли заметки.
Чтобы в торрентах, скачаных с rutracker получать списки скачивающих/раздающих хорошо бы иметь доступ к ретрекерам. Их не так уж и много:
bt.t-ru.org
bt2.t-ru.org
bt3.t-ru.org
bt4.t-ru.org
Заодно с этим и статистика розданного начнёт учитываться. Доступ к ним можно получить просто перенаправляя трафик, адресованый ретрекерам через прозрачную проксю.
Для этого в OpenWRT LuCI заходим в СетьМежсетевой экранCustom Rules и добавляем всего одну строку.
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -d 195.82.146.120/30 -j DNAT --to-destination 163.172.167.207:3128

Сохраняем, применяем. Всё!

mplayer4anime

3:25 Опубликовал Дмитрий Исаенко , , Нет комментариев
mplayer4anime — это фронт-энд к плееру mplayer. Если ищите удобный способ запускать mkv и mka одновременно — это как раз оно!
Задача проста, заменить bash-скрипты для запуска связок mkv+mka+субтитров. Почему это нужно? Ну, например, чтобы продолжать раздавать торренты в том виде, в котором они были скачаны. Конечно, в интересах удобства сразу в голову придёт идея объединить mkv и mka в один контейнер используя mkvmerge, но тогда не получится посидеть на раздаче или придётся жертвовать свободным местом на диске.

В итоге, этот «агрегатор» даёт возможность без лишних телодвижений загрузить весь сезон аниме в список и не городить очередной велосипед. 

GUI, ня!


Системные требования: JRE-1.8 (8) или выше.
Протестировано в Gentoo (virtual/jre 1.8.0-r1) и Debian Stretch (стандартный образ + openjfx).

Лицензия: GNU GPL v3.
Пиктограммы: material design.
Прочая графика: работы находящиеся в общественном достоянии или распространяющиеся по лицензии CC0 + собственные работы.

Версия на данном этапе вполне рабочая, но некоторые экстра-плюшки всё ещё не реализованы, например drag-n-drop.

И ещё, работает всё именно с mplayer а не с mpv или smplayer (хотя хотелось бы), так что подучите команды mplayer (f - полноэкранный режим, enter - закрыть, пробел - пауза).
Линка: https://github.com/developersu/mplayer4anime

Ах да, в будующих релизах будет добавлена поддержка Windows и, вероятно, безшовный запуск (отдельно устанавливать javaFX/JRE не потребуется). На macOS должно и так работать. Скажите мне если вдруг решитесь попробовать!

Ооо.. вот ещё, если вам вдруг понравилось, оставьте коммент! А даже если не понравилось, то тоже можно =)

7 марта 2018 г.

Deban stretch: возвращаем старые имена сетевых интерфейсов

7:34 Опубликовал Дмитрий Исаенко Нет комментариев
После загрузки systemctl status показывал мне статус degraded. Хотелось разобраться, что ему не нравится. Как оказалось, проблема была в именах сетевых интерфейсов которые генерировались автоматически. Что же, настало время венуть привычные вместо enp0s1 и т.п.
Приступим!

# systemctl status
...
    State: degraded
...

# systemctl
...
networking.service    loaded failed failed    Raise network interfaces
...
Исправляем добавив правило в udev.
# vim /etc/udev/rules.d/10-rename-network.rules
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="ff:ff:ff:ff:ff:ff", NAME="eth0"
Теперь исправим наши настройки автозагрузки поменяв имя интерфейса:
# vim /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto eth0
allow-hotplug eth0
iface eth0 inet dhcp
И после перезагрузки всё будет как надо!

1 марта 2018 г.

Заметки о вытаскивании дорожек из mkv и создании mka

0:50 Опубликовал Дмитрий Исаенко , Нет комментариев
Есть задача — вытащить аудио-дорожку из одного mkv файла и сделать из неё mka файл. Таким образом можно было бы использовать экспортированный дубляж в другом, более качественном видео-файле. Итак, нам понадобится mkvtoolnix. Ставим:
# emerge media-video/mkvtoolnix
Далее получаем информацию о файле-доноре. В нём ищем информацию о звуковых дорожках внутри матрёшки.
$ mkvinfo ./anime.mkv
+ Заголовок EBML
|+ Версия EBML: 1
...
...
| + Дорожка
|  + Номер дорожки: 2 (идентификатор дорожки для mkvmerge и mkvextract: 1)
|  + UID дорожки: 16263157260285453471
|  + Тип дорожки: audio
|  + Идентификатор кодека: A_MPEG/L3
|  + Продолжительность по умолчанию: 24.000ms (41.667 кадров/полей в секунду для видеодорожки)
|  + Язык: und
|  + Audio track
|   + Частота дискретизации: 48000
|   + Каналы: 2
|+ EbmlVoid (размер: 1095)
|+ Кластер
Тут важно обратить внимание на то, что подсвечено красным. В данном примере используется mp3 файл который имеет идентификатор 1 для mkvextract. Сейчас мы этим и воспользуемся. Вытаскиваем аудиодорожку в файл file.mp3.
$ mkvextract tracks ./anime.mkv 1:file.mp3
Извлечение дорожки 1 с CodecID 'A_MPEG/L3' в файл 'file.mp3'. Формат контейнера: MPEG-1 Audio Layer 2/3
Обработано: 100%
Также можем наверстать скриптик, который сделает рекурсивный обход всех файлов в папке и извлечёт из них заданые дорожки:
# vim script.sh
#!/bin/bash
for f in *.mkv
do
    mkvextract tracks "$f" 1:"$f".mp3
done

# chmod +x script.sh
# script.sh
Теперь воспользуемся GUI обёрткой над mkvtoolnix (mkvtoolnix-gui). Вы же собрали пакет с флагом qt5, верно? ;)
Выбираем файл (правой кнопкой клик на поле «Исходные файлы». Далее ставим нужный язык в одноимённом поле и жмём «Выполнить сборку».
На выходе получаем mka-файл. В моём случае подгонка по таймлайнам не требовалась, так что всё сразу заработало.

На этом всё!