LINUX.ORG.RU

Обсудить/улучшить/похвастаться bash'овым rss-радио

 , ,


0

4

Здравствуйте. Сделал скрипт, читающий rss-поток вслух.

Алгоритм такой: скрипт тянет из интернета поток, преобразует его в формат «одна новость - одна строка», после чего читает получившееся вслух, построчно чередуя голоса.

Формат запуска: «имя_скрипта $url»

Впилена фишка для зацикленного фонового режима или запуска по cron (для предотвращения одновременного запуска нескольких копий используется flock): перед прочтением вслух скрипт пробивает текст на повторяемость, удаляя все новости, которые уже были прочитаны.

Интересует возможность оптимизации чего-либо в нижеизложенном, ибо вполне мог реализовать что-либо не самым лучшим образом.

Предполагается наличие xmlstarlet, elinks, RHVoice (небольшой правкой кода голосовой движок легко заменяется на другой).

if ( ping -c 1 "ya.ru" > /dev/null 2>&1 );then
	if [ "$2" == 'text' ];then
		mv ~/tmp/rss ~/tmp/rss.old
		wget -O - $1 | xmlstarlet sel -t -m /rss/channel/item  -o 'new_article' -v title -o ' ' -v description | elinks -no-references -dump-width 1000 | sed -e :a -e 's/<[^>]*>//g;/</N;//ba'  | tr '\n' ' ' | tr -s [:blank:] | awk 'NF>0' | sed -e 's/new_article/\n/g' | tail -n +2 > ~/tmp/rss
		text="$(cat ~/tmp/rss)"
		while read linecheck;do 
			text="$(grep  -a -v "$linecheck" <<< "$text")"
		done < ~/tmp/rss.old
		echo "$text"
	else
		voice1='-s aleksandr -p -0.r -r 0.35'
		voice2='-s anna -p 0 -r -0.15'
		voice=`echo $voice1$'\n'$voice2 | shuf | head -n 1`
		while read string;do
			if [ "$voice" == "$voice1" ];then
				amixer set Master 3%+
				voice=$voice2
			else	
				amixer set Master 3%-
				voice=$voice1
			fi
			echo $string | RHVoice-client $voice | aplay > ~/tmp/voiceerr 
		done <<< "$(rss.sh $1 text)"
	fi
fi

Спасибо за внимание.

Ответ на: комментарий от dexpl

Нуу

Так-то может и не нужно.

Может, на каком-нибудь питоне это можно было бы исполнить более изящно, бгг. Только я не знаю питон, а в командную строку более-менее могу.

Для «тяп-ляп для собственных нужд» баш, как по мне - вне конкуренции)

piyavking ★★★ ()
Последнее исправление: piyavking (всего исправлений: 1)

На строку sed | tr | awk | sed даже смотреть не хочется. Но вот и shuf тоже для bash лишний:

voice1='-s aleksandr -p -0.r -r 0.35'
voice0='-s anna -p 0 -r -0.15'
voice=voice$((RANDOM > 32767/2))
while read string;do
	if [ $voice == voice1 ];then
		amixer set Master 3%+
	else	
		amixer set Master 3%-
	fi
	echo $string | RHVoice-client ${!voice} | aplay > ~/tmp/voiceerr
done <<< "$(rss.sh $1 text)"

vodz ★★★★★ ()
Ответ на: комментарий от Deleted

Озвучка-то что - движок исправно читает то, что ему дают, текстовый выход команды тоже в порядке.

Строчка рождена пробами и ошибками - раньше тащил xmlstarlet'ом, но он давал артефакты в виде значительных и неприятных артефактов в тексте, curl не всё тащит, так что пришлось впилить wget -O -.

piyavking ★★★ ()
Ответ на: комментарий от piyavking

Строчка рождена пробами и ошибками

Оно у вас рождено крайне неправильно. С первой же строки достаточно написать так:

if ping -qc 1 "ya.ru" 2> /dev/null ; then

[:blank:] нельзя писать без кавычек:

$ mkdir tst; cd txt
$ touch a
$ echo [:blank:]
a
И вообще, вместо tr '\n' ' ' | tr -s [:blank:] лучше tr -s '\n[:blank:]' ' ', но так как там awk, то вообще это всё нафиг не надо, и
tr '\n' ' ' | tr -s [:blank:] | awk 'NF>0' | sed -e 's/new_article/\n/g'
можно заменить на
awk \ '
BEGIN { RS="new_article[[:blank:]]|new_article\n"}
{for(i=1;i<=NF;i++) { printf("%s", $i); if(i!=NF) printf(" ") }
 if(NF) printf("\n")}'

Особо доставляет, что вначале пишете во временный файл, потом его засовываете в переменную, а потом из это переменной читаем...

vodz ★★★★★ ()
Ответ на: комментарий от vodz

Спасибо за улучшения регулярных выражений! Я в них, честно говоря, не особо)

Особо доставляет, что вначале пишете во временный файл, потом его засовываете в переменную, а потом из это переменной читаем...

А вот тут не торопитесь улыбаться. Я ж писал: фильтрация уже прочитанного, то есть:

1. переносим файл "rss" в файл "rss.old"
2. читаем поток в файл "rss"
3. засовываем содержимое файла "rss" в переменную
4. фильтруем переменную, то есть последовательно выпиливаем из неё строки, наличествующие в "rss.old".
5. выдаём отфильтрованную переменную. скачанный файл "rss" при этом не меняется, и будет использован для фильтра при следующем прогоне скрипта, см. пункт 1.

Временные файлы - для формирования фильтра, переменная - для выдачи тотфильтрованного текстового выхлопа.

Вот именно эта процедура меня тоже интересует в плане оптимизации. Что-то типа: «команда файл1 файл2», выдающая строки файла1, которых нет в файл2. Я это сделал по-простому, через перебор и grep, но наверняка можно поизящнее.

piyavking ★★★ ()
Последнее исправление: piyavking (всего исправлений: 1)
Ответ на: комментарий от piyavking

1. переносим файл «rss» в файл «rss.old»
2. читаем поток в файл «rss»

По идее не нужен вообще rss.old. Читаем в переменную rss, сравниваем с файлом rss, находим разницу, записываем новый файл rss из переменной rss.

Найти новые просто:

diff=$(awk '{seen[$0]++} END {for(i in seen) if(seen[i]==1) print i}' << EOF
$(echo "$rss")
$(cat rss)
EOF
)

vodz ★★★★★ ()