0
<< предыдущая заметкаследующая заметка >>
03 ноября 2021
Рассказы в mp3

На спор со знакомым грелочником смастерил вчера скриптик для перегонки рассказов в mp3. Использовал речевой синтезатор Яндекса. Рассказы бил на фразы и собирал в порции по 1000 букв, потому что там такое ограничение. Рассказов больше 200, за ночь все было готово. Думал, не хватит моего ключа API - помнится, там было какое-то ограничение, не более 1000 обращений в месяц или что-то вроде того. Но ключ выдержал. Яндекс, дай мне неограниченный ключ для подобных некоммерческих экспериментов?

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

Группа 1: https://disk.yandex.ru/d/oB-3_cFYsTwNnQ
Группа 2: https://disk.yandex.ru/d/1k94b3IgyuxDrQ
Группа 3: https://disk.yandex.ru/d/rtGvzbFyCFrMnw
Группа 4: https://disk.yandex.ru/d/9rDrE6uprKdd5Q
Группа 5: https://disk.yandex.ru/d/wRp8nsbqIGw99g

Даже "Гуси-лебеди" из второй группы. Нет, не мой. Я в этот раз не участвую - прорыв трубы и ремонт не оставил времени.

Собственно, пишу я это пост лишь для того, чтобы выложить сюда код, который превращает всю Грелку в mp3 - он совсем коротенький. Может, вам кому пригодится, да и мне полезно такие вещи хранить в дневнике, а то потеряется, а где потом искать, если понадобится что-то в звук перегнать:


<?php

#!/usr/bin/php

<?php

// впишите ваш ключ речевого API Яндекса:
$API="ae31d6fb-f342-4501-8648-7e4bea9dedb4";
// титульная страница нынешней Грелки:
$GRELKA='http://www.leningrad.su/makod/texts/k211_competition.htm';


$list='/tmp/grelka.htm';
if(!
is_file($list)) file_put_contents($list,file_get_contents($GRELKA));
$s=file_get_contents($list);
$s=wu($s);

$m=explode("<p><center><h4>",$s);

foreach(
$m as $num=>$l) {

    if(    
preg_match_all("/(\d+)\. \(\d+\) <a href=\"(.+?)\">(.+?)<\/a>/s",$l,$e) ) {
    
$gd="Группа ".$num;
    if(!
is_dir($gd)) mkdir($gd);
    echo 
"\n\n === ".$gd;

    foreach(
$e[0] as $i=>$l) {
        
$nm=$e[1][$i];
        
$url="http://www.leningrad.su".$e[2][$i];
        
$name=trim($e[3][$i]);
        
$to=$gd."/".sprintf("%02d",$nm)." ".$name.".txt";

        echo 
"\n $url [$name] -> ".$to;

        if(
is_file($to)) $txt=file_get_contents($to);
        else {
            
$txt=file_get_contents($url);
            
$txt=wu(ochictka($txt));
            
file_put_contents($to,$txt);
        }

        
say_text($gd."/".sprintf("%02d",$nm)." ".$name,$txt);
    }
    }

}

function 
wu($s) { $s=strtr($s,chr(152),'@'); return(iconv("windows-1251","utf-8//IGNORE",$s)); }
function 
uw($s) { return(iconv("utf-8","windows-1251//IGNORE",$s)); }

function 
ochictka($s) {
    
$s=str_replace("\r",'',$s);
    
$s=str_replace(' ',' ',$s);
    
$s=str_replace('&quot;','"',$s);
    
$s=str_ireplace('<p align="justify">','<p>',$s);
    
$s=str_ireplace('</p>','',$s);
    
$s=str_ireplace('<p>','',$s);
    if(!
preg_match("/<hr>.+?<hr>(.+?)<hr>/s",$s,$m)) die("No body!"); $s=$m[1];
    if(!
preg_match("/<h3><center><b>(.+?)<\/b><\/h3><\/center>(.+?)$/s",$s,$m)) die("No Header!"); $head=$m[1]; $s=$m[2];
    return 
$head."\n\n".$s;
}

function 
say($text,$out) { // собственно процедура озвучки: даем ей текст и имя файла
    
if(empty($text)) return;
    
$url="https://tts.voicetech.yandex.net/generate";
    
$ch curl_init($url);
    
curl_setopt ($chCURLOPT_USERAGENT'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3');
    
curl_setopt ($chCURLOPT_POST1);
    
curl_setopt ($chCURLOPT_POSTFIELDS,
            
"format=mp3" // mp3 — MPEG-1 Layer 3; wav — PCM; opus — OGG
            
."&lang=ru-RU" // ru&#8209;RU русский язык; en-US английский язык; tr-TR турецкий язык; uk-UK украинский язык.
            
."&speaker=ermil" // женские: jane, oksana, alyss и omazh; мужские: zahar, ermil
            
."&emotion=good" // good — радостный; evil — раздраженный; neutral — нейтральный
            
."&key=".$GLOBALS['API'// гуглите, как получить ключ у Яндекса, я не помню уже
            
."&text=".urlencode($text)); // Ограничение на длину: 2000 байт. Но я беру 1000.
    
curl_setopt ($chCURLOPT_RETURNTRANSFER1);
    
curl_setopt ($chCURLOPT_SSL_VERIFYPEER0);
    
curl_setopt ($chCURLOPT_SSL_VERIFYHOST0);
    
curl_setopt ($chCURLOPT_HTTPHEADER, array('Expect:')); // не высылать заголовок на ожидание
    
curl_exec ($ch);
    
$result=curl_multi_getcontent($ch);
    
curl_close ($ch);
    if(empty(
$result)) die('Error');
    
file_put_contents($out,$result);
}


function 
say_text($dir,$s) {
    if(!
is_dir($dir)) mkdir($dir);

    
$s=uw($s);
    
$LIM=1000// ограничение по количеству байт в каждом отрезке

    // будем разбивать текст на строки, а затем и собирать подходящие порции для озвучки

    
$u=explode("\n",$s);
    
$e=array();
    for(
$i=0;$i<sizeof($u);$i++) {
    
$l=$u[$i];
        while(
strlen($l)>$LIM) {
        
$j=$LIM; while($j && !in_array($l[$j],array('.','?','!'))) $j--;
            
$e[]=substr($l,0,$j+1);
            
$l=trim(substr($l,$j+1));
        }
    
$e[]=$l;
    }

    
$k=1$i=0;
    while(isset(
$e[$i])) {
    
$o=''; while(isset($e[$i]) && strlen($o.$e[$i])<=$LIM$o.=$e[$i++]."\n";
        
$out=$dir."/".sprintf("%03d",$k++).".txt";
    if(!
strlen($o)) $o.=$e[$i++]."\n";
        echo 
"\n[$out] (".strlen($o).")---\n".wu($o);
        
file_put_contents($out,$o);
    
$mp3=str_replace(".txt",".mp3",$out);
        if(!
is_file($mp3)) say(wu($o),$mp3); // озвучить очередную порцию mp3
    
}

    
// и наконец соберем все готовые куски mp3 в единый файл тупо консольным ffmpeg:
    
$r=glob($dir."/*.mp3"); foreach($r as $n=>$l$r[$n]=basename($l);
    
$mymp3=basename($dir).'.mp3';
    
$r='cd "'.$dir.'"; ffmpeg -i "concat:'.implode('|',$r).'" -acodec copy "../'.basename($dir).'.mp3"';
    
exec($r);
}
<< предыдущая заметка следующая заметка >>
пожаловаться на эту публикацию администрации портала
архив понравившихся мне ссылок