外挂式显歌词脚本(支持Rhythmbox)(7.23日更新)

sh/bash/dash/ksh/zsh等Shell脚本
头像
xiooli
帖子: 6956
注册时间: 2007-11-19 21:51
来自: 成都
联系:

外挂式显歌词脚本(支持Rhythmbox)(7.23日更新)

#1

帖子 xiooli » 2008-05-28 19:32

感谢ee,感谢solcomo,感谢CCTV,感谢ubuntu中文论坛。。。。
---------------------7.23日更新-----------------
没有作什么变化,按照ee的莫名其妙的提示用gzexe压了一个玩玩。

---------------------6.20日更新-----------------
Alpha.Roc 写了:一些在非中文语言设置环境下使用的问题,语言环境为英语:
1。系统在转换gb变量时,会自动在字符串结尾加上 %0a% ,不清楚原因,只好添加了一段 sed 's/%0a%//' 做替换。
2。gb 转换时使用 gb2312 似乎不能转换繁体字标题的歌曲,转为使用 gb18030,似乎能解决此问题。
已经更改代码:D

---------------------6.14日更新-----------------

修正了当歌词里面有*时会把当前目录的所有文件名显示出来的问题
改进了获得歌曲题目的代码(这有赖于solcomo的mlrc脚本的启发)
现在任何时候启动脚本均可显示歌词了

---------------------6.1日更新-------------------

改进了搜索算法,现在显示歌词完全不产生临时文件了。
精简了代码,效率明显提高 :)

------------------------------------------------------

1,信息直接从dbus-monitor中读取,故而理论上其他的播放器也可以支持,不过我只有Rythmbox可供做试验,如果需要的话可以

代码: 全选

dbus-monitor
然后切换播放歌曲,然后贴出终端输出,我看看可以根据该播放器的特征改下,或者你自己改也行。

2,因为mpd/mpc不是用dbus-monitor传递信息,故而不支持,用mpd/mpc的筒子可以另外去下另一个solcomo写的脚本:viewtopic.php?t=124574

3,不要sh ./lrcdis这样运行,先下载附件》解压》chmod +x ./lrcdis》./lrcdis

4,默认采用gnome-osd显示,需要安装之,直接

代码: 全选

sudo apt-get install gnome-osd
如果不安装gnome-osd那么会从终端输出(未经测试:)

5,默认lrc文件下载到~/.lyrics文件夹,可以自己改。歌词是从百度下载的。

6,可能有很多bug,个人测试有限,欢迎大家踊跃当小白鼠:D

代码: 全选

#!/bin/bash

#******************
# coded by xiooli
#******************

LRCDIR=~/.lyrics  #lrc文件保存文件夹,可以自己改
[ ! -d "$LRCDIR" ] && mkdir "$LRCDIR"

#下载歌词的函数
DOWNLRC(){ 
	NM="$1"
	#判断当前locale,utf-8的locale将要使用编码转换
	[ `locale |grep "LANG=.*UTF-8"` ] && lang=1
	#将歌曲名字转换为urlencode,utf-8的locale必须先转换为gb的编码
  	if [ "$lang" ];then
		#od的输出为每行16组,如果太长则会截断成两行,故而应该删除可能出现的换行符。
    		gb=`echo "$NM" | iconv -c -f utf-8 -t gbk | od -t x1 -A n |tr "\n" " " |tr " " % |sed 's/%%/%/g;s/%0a%$//'`
  	else
    		gb=`echo "$NM" | od -t x1 -A n |tr "\n" " " |tr " " % |sed 's/%%/%/g;s/%0a%$//'`
  	fi
	#从百度搜索里面找出当前歌曲的歌词下载页
  	wget "http://www.baidu.com/s?wd="$gb"+filetype%3Alrc&cl=3" -O /dev/shm/lrc_file  -T 10 -q
	
	LINK=`cat /dev/shm/lrc_file |grep "LRC" |awk -F"href="" '{print $2}' |awk -F""" '{print $1}'`
	
  	while [ "$LINK" ] && [ ! -s "$LRCDIR/$NM.lrc" ];do
		if [ "$lang" ];then
			wget "$LINK" -O /dev/shm/lrctmp  -T 5 -t 2 -q
			[ -s /dev/shm/lrctmp ] && iconv -f gbk -t utf-8 -c /dev/shm/lrctmp -o "$LRCDIR/$NM.lrc"
		else
			wget "$LINK" -O "$LRCDIR/$NM.lrc"  -T 5 -t 2 -q
		fi
		[ -s "$LRCDIR/$NM.lrc" ] && sed -i'' "s/\r/\n/g" "$LRCDIR/$NM.lrc" #去掉dos字符
		> /dev/shm/lrctmp
	done
	
}

#获取当前播放的歌曲标题
GET_TITLE() {
	
	TITLE=`dbus-send --session --print-reply --dest=org.gnome.Rhythmbox /org/gnome/Rhythmbox/Player org.gnome.Rhythmbox.Player.getPlayingUri \
|grep "string" |perl -p -e 's/%(..)/pack("c", hex($1))/eg' |awk -F"." '{ i=1;while(i<NF) {printf $i".";i++}}' \
|sed 's/.*\///g;s/\.$//'` && title_changed=1

}

#分割lrc文件的函数(仅取出时间信息并转换成秒)
LRC_SPLIT() {
	tm_arr=`cat "$1" |grep "\[[0-9]" |while read LINE
		do
			echo $LINE |sed "s/\[0/\[/g;s/\]\[/ /g;s/\[//g;s/\][^\[].*//g;s/:0/:/g;s/\]//g"
		done` 
	for i in ${tm_arr[@]};do
		min=`echo $i |sed 's/:.*//'`
		sec=`echo $i |sed 's/\..*//;s/^.*://'`
		echo $(($min*60+$sec))
	done

}

#根据播放时间找出lrc中对应的时间(lrc时间中小于播放时间的最大时间)
FIND_LRC_TIME() {
	if [ "${TIME_LIST[0]}" ];then	
		pltm="$1"
		let tmp=-1
		for lrctm in ${TIME_LIST[@]};do
			if [ "$tmp" -lt "$pltm" ] && [ "$tmp" -lt "$lrctm" ] && [ "$pltm" -ge "$lrctm" ];then
				let tmp="$lrctm" 
			fi
		done
	fi
	[ "$tmp" ] && printf '%.2d:%.2d' $(($tmp/60)) $(($tmp%60))
}

#osd模式显示(未安装gnome-osd则终端输出)
let n=1
OSD_SHOW() {
	if [ `which gnome-osd-client` ];then
		gnome-osd-client -f "<message id='lrcdis' hide_timeout='10000'>`echo "$*"`</message>"
	else	
		[ "$n" -eq 1 ]  && clear && echo  -e "\033[;32m******"$TITLE"****** \033[0m " && let n=5
		echo "$*" && let n="$n"-1
	fi
}

#显示歌词函数
DISPLAY() {
	if [ "$1" ] && [ "$2" ];then
		lrc_line=`printf "$1" |awk -F"$2" '{print $2}' |sed "s/@.*//g;s/^.*\]//g;s/*/\\\*/g"`
		if [ "$lrc_line" ] && [ "$line" != "$lrc_line" ];then
			OSD_SHOW "$lrc_line" 
			line="$lrc_line"
		fi
	fi
}

MAIN() {

	GET_TITLE
	dbus-monitor --session |while read a;do
		
		[ "$a" = "byte 0" ] && killall dbus-monitor && break #dbus会在歌曲变化时会输出一堆(上千行)byte 0,此时先跳出循环,歇会儿。
		[ "`echo "$a" |grep "^uint"`" ] || continue

		if [ "$a" = "uint32 0" ];then
			LRC=""
			TIME_LIST=""
		elif [ "$a" = "uint32 1" ];then
			go_on=1
		else
			go_on=2
		fi
	
		#找到歌曲题目
		if    [ "$go_on" = 1 ];then
	
			[ "$title" != "$TITLE" ] && title="$TITLE" && GET_TITLE		
			go_on=""
		fi
	
		if [ "$title_changed" ];then
		
			[ `which gnome-osd-client` ] && OSD_SHOW "******"$TITLE"******"
			notfound="no" && TIME_LIST="" && TIME="0" && sleep 1
			[ -s "$LRCDIR/$TITLE.lrc" ] && TIME_LIST=($(LRC_SPLIT "$LRCDIR/$TITLE.lrc")) \
			&& LRC=$(cat "$LRCDIR/$TITLE.lrc" |grep "^\[" |tr "\n" "@" )
			title_changed=""
	
		fi
		
		[ "$notfound" = yes ] && continue
	
		#下载歌词
		if [ ! -s "$LRCDIR/$TITLE.lrc" ] && [ "$TITLE" ];then
	
			DOWNLRC "$TITLE"
			[ ! -s "$LRCDIR/$TITLE.lrc" ] && OSD_SHOW "$TITLE:未找到lrc文件" && notfound="yes"
			[ -s "$LRCDIR/$TITLE.lrc" ] && TIME_LIST=($(LRC_SPLIT "$LRCDIR/$TITLE.lrc"))\
			&& LRC=$(cat "$LRCDIR/$TITLE.lrc" |grep "^\[" |tr "\n" "@" )
	
		fi
	
		#取得播放时间并显示歌词
		if [ "$go_on" = 2 ];then
	
			t=`echo "$a" |sed 's/.*\ //g'`
			[ "$t" ] && [ -s "$LRCDIR/$TITLE.lrc" ] && TIME="$(FIND_LRC_TIME "$t")" && t="" \
			&& DISPLAY "$LRC" "$TIME"
			go_on=""
		fi
	
	done
}

#*******main******
while true;do
	MAIN
	sleep 1.5
done


:D
附件
lrcdis.tar.gz
经过gzexe压缩过的
(2.89 KiB) 已下载 304 次
lrcdis.tar.gz
未压缩的
(2.32 KiB) 已下载 688 次
上次由 xiooli 在 2008-07-23 17:24,总共编辑 13 次。
头像
xiooli
帖子: 6956
注册时间: 2007-11-19 21:51
来自: 成都
联系:

#2

帖子 xiooli » 2008-05-28 19:33

来张图:
附件
Screenshot.png
头像
fengjie
帖子: 130
注册时间: 2008-03-19 14:20

#3

帖子 fengjie » 2008-05-28 19:38

感谢分享,学习中
主板:ASUS P8Z77-V
CPU:Intel 酷睿i3 3200
内存:ADTA DDRⅢ 1600 8G
显卡:Intel® HD Graphic
声卡:Realtek ALC 892
有线网卡:Intel® 82579V
无线网卡:Qualcomm Atheros AR9485
硬盘:WDC WD6401AALS
电源:长城ATX-350SD静音大师
显示器:Samsung S24A350H
头像
solcomo
帖子: 2838
注册时间: 2007-04-25 13:12

#4

帖子 solcomo » 2008-05-28 19:40

这么快就弄出来了 :D 我还在研究呢
♜♞♝♛♚♝♞♜
♟♟♟♟♟♟♟♟
♙♙♙♙♙♙♙♙
♖♘♗♕♔♗♘♖

☠☯⚔⚓☣☦☃☕
☹☻☪☭☬⚖⚛⚜
ℜℳℬ™ ℋℯℓ℘ ℳℭ
sƂɐʍ рǀɹoʍ əɥʇ oS
头像
xiooli
帖子: 6956
注册时间: 2007-11-19 21:51
来自: 成都
联系:

#5

帖子 xiooli » 2008-05-28 19:45

哦对了,最好把osd的notifications的notify on song changes关掉,不然可能会有小错误(可能会在歌曲改变后一段时间发生歌词显示错误的问题,这是因为osd的server在歌曲改变的时候也会往dbus里面发消息)
头像
xiooli
帖子: 6956
注册时间: 2007-11-19 21:51
来自: 成都
联系:

#6

帖子 xiooli » 2008-05-28 19:46

solcomo 写了:这么快就弄出来了 :D 我还在研究呢
哈哈,乱蒙的,居然让我给弄成功了 :D
头像
solcomo
帖子: 2838
注册时间: 2007-04-25 13:12

#7

帖子 solcomo » 2008-05-28 20:24

有一个问题...标题打错了 ...rhythmbox 8)
♜♞♝♛♚♝♞♜
♟♟♟♟♟♟♟♟
♙♙♙♙♙♙♙♙
♖♘♗♕♔♗♘♖

☠☯⚔⚓☣☦☃☕
☹☻☪☭☬⚖⚛⚜
ℜℳℬ™ ℋℯℓ℘ ℳℭ
sƂɐʍ рǀɹoʍ əɥʇ oS
头像
xiooli
帖子: 6956
注册时间: 2007-11-19 21:51
来自: 成都
联系:

#8

帖子 xiooli » 2008-05-28 20:27

solcomo 写了:有一个问题...标题打错了 ...rhythmbox 8)
哦?不好意思,多谢提醒 :lol:
头像
eexpress
帖子: 58428
注册时间: 2005-08-14 21:55
来自: 长沙

#9

帖子 eexpress » 2008-05-28 23:12

额。这家伙最近太勤奋了啊。真是个突破。也是个人的突破啊。以后,疑难杂症的,都找你了啊。 :lol:
支持。
● 鸣学
头像
xiooli
帖子: 6956
注册时间: 2007-11-19 21:51
来自: 成都
联系:

#10

帖子 xiooli » 2008-05-28 23:39

哈哈,能得ee用神的语言表扬一番,那是相当有面子啊 :D
头像
eexpress
帖子: 58428
注册时间: 2005-08-14 21:55
来自: 长沙

#11

帖子 eexpress » 2008-05-28 23:47

61行的 for i in `cat /dev/shm/lrc_time.list |grep "$pltm_min:"`;do
会报错的。/dev/shm/lrc_time.list 文件不存在。
应该是逻辑次序需要改进。
还有提示下载失败的,接着就不再出任何下载失败的提示了。

109行的 下载那里,加一个dn=4就不执行的判断吧。开始有问题,调试了下,这里频繁被调用哦。节约点吧。 :lol:

判断时间有问题。出了一整歌曲的int数字。呵呵。
● 鸣学
头像
xiooli
帖子: 6956
注册时间: 2007-11-19 21:51
来自: 成都
联系:

#12

帖子 xiooli » 2008-05-28 23:51

eexpress 写了:61行的 for i in `cat /dev/shm/lrc_time.list |grep "$pltm_min:"`;do
会报错的。/dev/shm/lrc_time.list 文件不存在。
应该是逻辑次序需要改进。
还有提示下载失败的,接着就不再出任何下载失败的提示了。

109行的 下载那里,加一个dn=4就不执行的判断吧。开始有问题,调试了下,这里频繁被调用哦。节约点吧。 :lol:

判断时间有问题。出了一整歌曲的int数字。呵呵。
恩,我再看看吧,主要是我这儿基本上的歌词都有,所以下载的那一块没太在意。
头像
solcomo
帖子: 2838
注册时间: 2007-04-25 13:12

#13

帖子 solcomo » 2008-05-29 8:36

..昨天装了半天Rhythmbox就是弄不好...依赖太多了 :em80
最后装了个audacious...
dbus-monitor可以得到这样的东西

代码: 全选

   array [
      dict entry(
         string "title"
         variant             string "Where Did You Sleep Last Night"
      )
      dict entry(
         string "artist"
         variant             string "Nirvana百事高Bressanone"
      )
      dict entry(
         string "length"
         variant             int32 306181
      )
      dict entry(
         string "URI"
         variant             string "file:///home/como/Music/where_did_you_sleep_last_night.mp3"
      )
用grep 'string' | awk -F'"' '{printf $2}'可以弄成这样

代码: 全选

title
Where Did You Sleep Last Night

artist
Nirvana百事高Bressanone

codec
MPEG-1 Audio Layer 3
然后用sed搜索title并输出匹配它的下一行不好使 :em20
你那句perl我又看不懂....汗呐
♜♞♝♛♚♝♞♜
♟♟♟♟♟♟♟♟
♙♙♙♙♙♙♙♙
♖♘♗♕♔♗♘♖

☠☯⚔⚓☣☦☃☕
☹☻☪☭☬⚖⚛⚜
ℜℳℬ™ ℋℯℓ℘ ℳℭ
sƂɐʍ рǀɹoʍ əɥʇ oS
头像
xiooli
帖子: 6956
注册时间: 2007-11-19 21:51
来自: 成都
联系:

#14

帖子 xiooli » 2008-05-29 9:34

xiooli 写了:哦对了,最好把osd的notifications的notify on song changes关掉,不然可能会有小错误(可能会在歌曲改变后一段时间发生歌词显示错误的问题,这是因为osd的server在歌曲改变的时候也会往dbus里面发消息)
ls有没有关那个啊?有可能是osd发的信息(因为我看起来很熟),如果是的话关掉再看看。
另:那句perl就是把urlencode转换成汉字的,不用管它。
头像
solcomo
帖子: 2838
注册时间: 2007-04-25 13:12

#15

帖子 solcomo » 2008-05-29 9:42

xiooli 写了:
xiooli 写了:哦对了,最好把osd的notifications的notify on song changes关掉,不然可能会有小错误(可能会在歌曲改变后一段时间发生歌词显示错误的问题,这是因为osd的server在歌曲改变的时候也会往dbus里面发消息)
ls有没有关那个啊?有可能是osd发的信息(因为我看起来很熟),如果是的话关掉再看看。
另:那句perl就是把urlencode转换成汉字的,不用管它。
不是osd的问题...是根本放不了歌...老提示插件错误...
♜♞♝♛♚♝♞♜
♟♟♟♟♟♟♟♟
♙♙♙♙♙♙♙♙
♖♘♗♕♔♗♘♖

☠☯⚔⚓☣☦☃☕
☹☻☪☭☬⚖⚛⚜
ℜℳℬ™ ℋℯℓ℘ ℳℭ
sƂɐʍ рǀɹoʍ əɥʇ oS
回复