add song lyric, add playlist link, fix expired url bug

This commit is contained in:
listen1 2016-05-08 09:28:11 +08:00
parent 266b9aba33
commit 12f70accc7
11 changed files with 405 additions and 85 deletions

View File

@ -1,4 +1,4 @@
Listen 1 (Chrome Extension) 五一先行版
Listen 1 (Chrome Extension) 最后更新于5月8日
==========
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)
@ -26,6 +26,20 @@ Listen 1 (Chrome Extension) (五一先行版)
3. 选择 `加载已解压的扩展程序`(如果没有显示先选中`开发者模式`),选中解压后的文件夹,完成!
更新日志
-------
`2016-05-08`
* 增加歌词显示
* 精选歌单:添加歌单到当前播放列表,可点击跳转到原始链接
* 修复了循环播放网易歌曲一段时间后暂停的bug
* 修复了可能导致微信公众号无法登录的bug
* 优化性能,删除了不必要的事件消息触发
`2016-05-02`
* 增加音量控制
TODO
----
加入我的歌单功能如迫不及待需要可以安装Listen 1非插件版

View File

@ -496,15 +496,18 @@ em, i {
_bottom: 90px;
right: 0px;
_right: 0px;
width: 60%;
height: 301px;
height: 330px;
width: 100%;
background-color: #121212;
}
.m-playbar .menu ul {
display: inline-block;
padding-left: 0px;
height: 270px;
overflow: auto;
height: 290px;
overflow-y: scroll;
width: 60%;
margin-bottom: 0px;
}
.m-playbar .menu li {
@ -513,6 +516,28 @@ em, i {
display: block;
}
.m-playbar .menu .lyric {
text-align: center;
width: 39%;
display: inline-block;
height: 290px;
overflow-y: scroll;
position: relative;
}
.m-playbar .menu .lyric p{
min-height: 20px;
}
.m-playbar .menu .lyric .placeholder{
height: 50px;
}
.m-playbar .menu .lyric .highlight{
font-size: 15px;
color: #ffffff;
}
.m-playbar .menu .playing {
background-color: #555555;
}
@ -522,8 +547,8 @@ em, i {
}
.m-playbar .menu .icn-remove {
height: 25px;
width: 25px;
height: 20px;
width: 20px;
background-position: -75px -25px;
display: inline-block;
}
@ -544,15 +569,37 @@ li {
}
.menu-header {
height: 28px;
background-color: #121212;
height: 40px;
background-color: #222222;
padding-top: 4px;
text-align: center;
}
.menu-header span {
position: absolute;
left: 19px;
top: 7px;
font-size: 18px;
color: #ffffff;
}
.menu .remove-all {
display: inline-block;
position: absolute;
left: 113px;
top: 9px;
}
.menu .close-popup {
float:right;
margin-right: 10px;
margin-right: 14px;
font-size: 20px;
text-decoration: none;
color: #aaaaaa;
}
.menu .close-popup:hover {
color: #ffffff;
}
.menu .title {
@ -636,23 +683,40 @@ li {
text-align: center;
}
.playlist-detail .detail-head-title .play {
.playlist-detail .detail-head-title a {
display: inline-block;
text-indent: -9999px;
width: 36px;
height: 36px;
margin-right: 8px;
margin-top: 0;
background-position-x: 0;
background: url(../images/player_large.png) no-repeat 0 9999px;
}
.playlist-detail .detail-head-title .play {
background-position: 0px 0px;
}
.playlist-detail .detail-head-title .play:hover {
background: url(../images/player_large.png) no-repeat 0 9999px;
background-position: 0px -36px;
}
.playlist-detail .detail-head-title .add {
background-position: -216px 0px;
}
.playlist-detail .detail-head-title .add:hover {
background-position: -216px -36px;
}
.playlist-detail .detail-head-title .link {
background-position: -256px 0px;
}
.playlist-detail .detail-head-title .link:hover {
background-position: -256px -36px;
}
.playlist-detail .detail-head-title .delete {
display: inline-block;
text-indent: -9999px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

172
js/app.js
View File

@ -72,6 +72,7 @@
$scope.resetWindow = function() {
$scope.cover_img_url = 'images/loading.gif';
$scope.playlist_title = '';
$scope.playlist_source_url = '';
$scope.songs = [];
};
@ -89,6 +90,7 @@
$scope.songs = data.tracks;
$scope.cover_img_url = data.info.cover_img_url;
$scope.playlist_title = data.info.title;
$scope.playlist_source_url = data.info.source_url;
$scope.list_id = data.info.id;
$scope.is_mine = data.is_mine;
});
@ -112,6 +114,7 @@
$scope.songs = data.tracks;
$scope.cover_img_url = data.info.cover_img_url;
$scope.playlist_title = data.info.title;
$scope.playlist_source_url = data.info.source_url;
});
}
};
@ -277,19 +280,34 @@
$scope.current_list_id = list_id;
};
$scope.$on('player:playlist', function(event, data) {
localStorage.setObject('current-playing', data);
});
$scope.playMylist = function(list_id){
$timeout(function(){
angularPlayer.clearPlaylist(function(data) {
//add songs to playlist
angularPlayer.addTrackArray($scope.songs);
var index = 0;
if (angularPlayer.getShuffle()) {
var max = $scope.songs.length - 1;
var min = 0;
index = Math.floor(Math.random() * (max - min + 1)) + min;
}
//play first song
angularPlayer.playTrack($scope.songs[index].id);
});
}, 0);
$scope.setCurrentList(list_id);
};
$scope.$on('track:id', function(event, data) {
var current = localStorage.getObject('player-settings');
current.nowplaying_track_id = data;
localStorage.setObject('player-settings', current);
});
$scope.addMylist = function(list_id){
$timeout(function(){
//add songs to playlist
angularPlayer.addTrackArray($scope.songs);
Notification.success("添加到当前播放成功");
}, 0);
};
}]);
app.controller('PlayController', ['$scope', '$timeout','$log',
'$anchorScroll', '$location', 'angularPlayer', '$http',
'$httpParamSerializerJQLike','$rootScope', 'Notification','loWeb',
@ -299,6 +317,8 @@
$scope.volume = angularPlayer.getVolume();
$scope.mute = angularPlayer.getMuteStatus();
$scope.settings = {"playmode": 0, "nowplaying_track_id": -1};
$scope.lyricArray = [];
$scope.lyricLineNumber = -1;
$scope.loadLocalSettings = function() {
var defaultSettings = {"playmode": 0, "nowplaying_track_id": -1, "volume": 90};
@ -419,23 +439,7 @@
angularPlayer.mute();
}
$scope.playmylist = function(list_id){
$timeout(function(){
angularPlayer.clearPlaylist(function(data) {
//add songs to playlist
angularPlayer.addTrackArray($scope.songs);
var index = 0;
if (angularPlayer.getShuffle()) {
var max = $scope.songs.length - 1;
var min = 0;
index = Math.floor(Math.random() * (max - min + 1)) + min;
}
//play first song
angularPlayer.playTrack($scope.songs[index].id);
});
}, 0);
$scope.setCurrentList(list_id);
};
$scope.removemylist = function(list_id){
var url = '/remove_myplaylist';
@ -494,6 +498,116 @@
$scope.$on('music:mute', function (event, data) {
$scope.mute = data;
});
$scope.$on('player:playlist', function(event, data) {
localStorage.setObject('current-playing', data);
});
function parseLyric(lyric) {
var lines = lyric.split('\n');
var result = [];
var timeResult = [];
var timeRegResult = null;
function rightPadding(str, length, padChar) {
var newstr = str;
for (var i=0; i< length - str.length; i++) {
newstr += padChar;
}
return newstr;
}
for (var i=0; i<lines.length; i++) {
var line = lines[i];
var tagReg = /\[\D*:([^\]]+)\]/g;
var tagRegResult = tagReg.exec(line);
if (tagRegResult) {
var lyricObject = {};
lyricObject.seconds = 0;
lyricObject.content = tagRegResult[1];
result.push(lyricObject);
continue;
}
var timeReg = /\[(\d{2,})\:(\d{2})(?:\.(\d{1,3}))?\]/g;
while(timeRegResult = timeReg.exec(line)) {
var content = line.replace(/\[(\d{2,})\:(\d{2})(?:\.(\d{1,3}))?\]/g, '');
var min = parseInt(timeRegResult[1]);
var sec = parseInt(timeRegResult[2]);
var microsec = parseInt(rightPadding(timeRegResult[3], 3, '0'));
var seconds = min * 60 * 1000 + sec*1000 + microsec;
var lyricObject = {};
lyricObject.content = content;
lyricObject.seconds = seconds;
timeResult.push(lyricObject);
}
}
// sort time line
timeResult.sort(function(a, b){
var keyA = a.seconds,
keyB = b.seconds;
// Compare the 2 dates
if(keyA < keyB) return -1;
if(keyA > keyB) return 1;
return 0;
});
// disable tag info, because music provider always write
// tag info in lyric timeline.
//result.push.apply(result, timeResult);
result = timeResult;
for (var i=0; i<result.length; i++) {
result[i].lineNumber = i;
}
return result;
}
$scope.$on('track:id', function(event, data) {
var current = localStorage.getObject('player-settings');
current.nowplaying_track_id = data;
localStorage.setObject('player-settings', current);
// update lyric
$scope.lyricArray = [];
$scope.lyricLineNumber = -1;
$(".lyric").animate({ scrollTop: "0px" }, 500);
var url = '/lyric?track_id=' + data;
var track = angularPlayer.getTrack(data);
if (track.lyric_url != null) {
url = url + '&lyric_url=' + track.lyric_url;
}
loWeb.get(url).success(function(data) {
var lyric = data.lyric;
$scope.lyricArray = parseLyric(lyric);
});
});
$scope.$on('currentTrack:position', function(event, data) {
// update lyric position
var currentSeconds = data;
var lastObject = null;
for (var i=0; i< $scope.lyricArray.length; i++) {
var lyricObject = $scope.lyricArray[i];
if (currentSeconds < lyricObject.seconds) {
break;
}
lastObject = lyricObject;
}
if (lastObject && lastObject.lineNumber != $scope.lyricLineNumber) {
var lineHeight = 20;
var lineElement = $(".lyric p")[lastObject.lineNumber];
var windowHeight = 270;
var offset = lineElement.offsetTop - windowHeight/2;
//$(".lyric").scrollTop(offset);
$(".lyric").animate({ scrollTop: offset+"px" }, 500);
$scope.lyricLineNumber = lastObject.lineNumber;
}
});
}]);
app.controller('InstantSearchController', ['$scope', '$http', '$timeout', 'angularPlayer', 'loWeb',
@ -595,16 +709,16 @@
};
}]);
app.directive('openSongSource', ['angularPlayer', '$window',
app.directive('openUrl', ['angularPlayer', '$window',
function (angularPlayer, $window) {
return {
restrict: "EA",
scope: {
song: "=openSongSource"
url: "=openUrl"
},
link: function (scope, element, attrs) {
element.bind('click', function (event) {
$window.open(scope.song.source_url, '_blank');
$window.open(scope.url, '_blank');
});
}
};

View File

@ -15,7 +15,10 @@ function hack_referer_header(details) {
referer_value = "http://m.xiami.com/";
}
if (details.url.indexOf(".qq.com/") != -1) {
if ((details.url.indexOf("y.qq.com/") != -1) ||
(details.url.indexOf("qqmusic.qq.com/") != -1) ||
(details.url.indexOf("music.qq.com/") != -1) ||
(details.url.indexOf("imgcache.qq.com/") != -1)) {
referer_value = "http://y.qq.com/";
}

View File

@ -4,9 +4,6 @@ ngloWebManager.factory('loWeb', ['$rootScope', '$log', '$http', '$httpParamSeria
function($rootScope, $log, $http, $httpParamSerializerJQLike) {
var response = null;
return {
foo: function(){
console.log('foo');
},
get: function(url) {
if (url.search('/show_playlist') != -1) {
var source = getParameterByName('source', url);
@ -69,13 +66,26 @@ function($rootScope, $log, $http, $httpParamSerializerJQLike) {
return qq_artist(url, $http, $httpParamSerializerJQLike);
}
}
if (url.search('/lyric') != -1) {
var track_id = getParameterByName('track_id', url);
if (track_id.search('xmtrack')!= -1) {
return xm_lyric(url, $http, $httpParamSerializerJQLike);
}
if (track_id.search('netrack')!= -1) {
return ne_lyric(url, $http, $httpParamSerializerJQLike);
}
if (track_id.search('qqtrack')!= -1) {
return qq_lyric(url, $http, $httpParamSerializerJQLike);
}
}
},
bootstrapTrack: function(sound, track, callback){
if (sound.url.search('http') != -1){
callback();
return;
}
// always refresh url, becaues url will expires
// if (sound.url.search('http') != -1){
// callback();
// return;
// }
if(track.source == 'xiami') {
xm_bootstrap_track(sound, track, callback, $http, $httpParamSerializerJQLike);
}

View File

@ -10,12 +10,15 @@ function ne_show_playlist(url, hm) {
var default_playlist = {
'cover_img_url' : '',
'title': '',
'list_id': ''
'list_id': '',
'source_url': ''
};
default_playlist.cover_img_url = $(this).find('img')[0].src;
default_playlist.title = $(this).find('div a')[0].title;
var url = $(this).find('div a')[0].href;
default_playlist.list_id = 'neplaylist_' + getParameterByName('id',url);
var list_id = getParameterByName('id',url);
default_playlist.list_id = 'neplaylist_' + list_id;
default_playlist.source_url = 'http://music.163.com/#/playlist?id=' + list_id;
result.push(default_playlist);
});
return fn({"result":result});
@ -35,7 +38,8 @@ function ne_get_playlist(url, hm) {
var info = {
'list_id': list_id,
'cover_img_url': dataObj.find('.u-cover img').attr('src'),
'title': dataObj.find('.tit h2').text()
'title': dataObj.find('.tit h2').text(),
'source_url': 'http://music.163.com/#/playlist?id=' + list_id
};
var tracks = [];
var json_string = dataObj.find('textarea').val();
@ -162,7 +166,7 @@ function _encrypted_request(text) {
function ne_bootstrap_track(sound, track, callback, hm, se) {
var target_url = 'http://music.163.com/weapi/song/enhance/player/url?csrf_token=';
var csrf = '';
var song_id = sound.url;
var song_id = track.id;
song_id = song_id.slice('netrack_'.length);
var d = {
@ -245,7 +249,8 @@ function ne_album(url, hm, se) {
var info = {
'cover_img_url': data.album.picUrl,
'title': data.album.name,
'id': data.album.id
'id': 'nealbum_' + data.album.id,
'source_url': 'http://music.163.com/#/album?id=' + data.album.id
};
var tracks = [];
@ -284,7 +289,8 @@ function ne_artist(url, hm, se) {
var info = {
'cover_img_url': data.artist.picUrl,
'title': data.artist.name,
'id': data.artist.id
'id': 'neartist_' + data.artist.id,
'source_url': 'http://music.163.com/#/artist?id=' + data.artist.id
};
var tracks = [];
@ -308,3 +314,35 @@ function ne_artist(url, hm, se) {
}
};
}
function ne_lyric(url, hm, se) {
var track_id = getParameterByName('track_id', url).split('_').pop();
// use chrome extension to modify referer.
var target_url = 'http://music.163.com/weapi/song/lyric?csrf_token=';
var csrf = '';
var d = {
'id': track_id,
'lv': -1,
'tv': -1,
'csrf_token': csrf
}
var data = _encrypted_request(d);
return {
success: function(fn) {
hm({
url: target_url,
method: 'POST',
data: se(data),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).success(function(data) {
var lrc = '';
if (data.lrc != null) {
lrc = data.lrc.lyric;
}
return fn({"lyric":lrc});
});
}
};
}

View File

@ -26,7 +26,9 @@ function qq_show_playlist(url, hm) {
var d = {
'cover_img_url': item.imgurl,
'title': htmlDecode(item.dissname),
'list_id':'qqplaylist_' + item.dissid
'list_id':'qqplaylist_' + item.dissid,
'source_url': 'http://y.qq.com/#type=taoge&id=' + item.dissid
};
playlists.push(d);
});
@ -89,7 +91,8 @@ function qq_get_playlist(url, hm) {
var info = {
'cover_img_url': data.cdlist[0].logo,
'title': data.cdlist[0].dissname,
'id': 'qqplaylist_' + list_id
'id': 'qqplaylist_' + list_id,
'source_url': 'http://y.qq.com/#type=taoge&id=' + list_id
};
var tracks = [];
@ -125,7 +128,8 @@ function qq_album(url, hm) {
var info = {
'cover_img_url': qq_get_image_url(album_id, 'album'),
'title': data.data.name,
'id': 'qqalbum_' + album_id
'id': 'qqalbum_' + album_id,
'source_url': 'http://y.qq.com/#type=album&mid=' + album_id
};
var tracks = [];
@ -162,7 +166,8 @@ function qq_artist(url, hm) {
var info = {
'cover_img_url': qq_get_image_url(artist_id, 'artist'),
'title': data.data.singer_name,
'id': 'qqartist_' + artist_id
'id': 'qqartist_' + artist_id,
'source_url': 'http://y.qq.com/#type=singer&mid=' + artist_id
};
var tracks = [];
@ -220,9 +225,47 @@ function qq_bootstrap_track(sound, track, callback, hm, se) {
data = data.slice('jsonCallback('.length, -');'.length);
data = JSON.parse(data);
var token = data.key;
var url = 'http://cc.stream.qqmusic.qq.com/C200' + sound.url.slice('qqtrack_'.length) + '.m4a?vkey=' +
var url = 'http://cc.stream.qqmusic.qq.com/C200' + track.id.slice('qqtrack_'.length) + '.m4a?vkey=' +
token + '&fromtag=0&guid=780782017';
sound.url = url;
callback();
});
}
}
function str2ab(str) {
// string to array buffer.
var buf = new ArrayBuffer(str.length);
var bufView = new Uint8Array(buf);
for (var i=0, strLen=str.length; i<strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function qq_lyric(url, hm, se) {
var track_id = getParameterByName('track_id', url).split('_').pop();
// use chrome extension to modify referer.
var target_url = 'http://i.y.qq.com/lyric/fcgi-bin/fcg_query_lyric.fcg?' +
'songmid=' + track_id +
'&loginUin=0&hostUin=0&format=jsonp&inCharset=GB2312' +
'&outCharset=utf-8&notice=0&platform=yqq&jsonpCallback=MusicJsonCallback&needNewCode=0';
return {
success: function(fn) {
hm({
url:target_url,
method: 'GET',
transformResponse: undefined
}).success(function(data) {
data = data.slice('MusicJsonCallback('.length, -')'.length);
data = JSON.parse(data);
var lrc = '';
if (data.lyric != null) {
var td = new TextDecoder('utf8');
lrc = td.decode(str2ab(atob(data.lyric)));
}
return fn({"lyric":lrc});
});
}
};
}

View File

@ -4574,6 +4574,14 @@ ngSoundManager.factory('angularPlayer', ['$rootScope', '$log',
return playlist[key];
}
},
getTrack: function(trackId) {
for (var i=0; i< playlist.length; i++) {
if (playlist[i].id == trackId) {
return playlist[i];
}
}
return null;
},
addToPlaylist: function(track) {
playlist.push(track);
//broadcast playlist

View File

@ -44,12 +44,15 @@ function xm_show_playlist(url, hm) {
var default_playlist = {
'cover_img_url' : '',
'title': '',
'list_id': ''
'list_id': '',
'source_url': ''
};
default_playlist.cover_img_url = $(this).find('img')[0].src;
default_playlist.title = $(this).find('h3 a')[0].title;
var xiami_url = $(this).find('h3 a')[0].href;
default_playlist.list_id = 'xmplaylist_' + xiami_url.split('?')[0].split('/').pop();
var list_id = xiami_url.split('?')[0].split('/').pop()
default_playlist.list_id = 'xmplaylist_' + list_id;
default_playlist.source_url = 'http://www.xiami.com/collect/' + list_id;
result.push(default_playlist);
});
return fn({"result":result});
@ -77,7 +80,8 @@ function xm_get_playlist(url, hm) {
var info = {
'cover_img_url': xm_retina_url(data.data.logo),
'title': data.data.collect_name,
'id': 'xmplaylist_' + list_id
'id': 'xmplaylist_' + list_id,
'source_url': 'http://www.xiami.com/collect/' + list_id
};
var tracks = [];
@ -92,7 +96,7 @@ function xm_get_playlist(url, hm) {
}
function xm_bootstrap_track(sound, track, callback, hm, se) {
var target_url = 'http://www.xiami.com/song/playlist/id/' + sound.url.slice('xmtrack_'.length) +
var target_url = 'http://www.xiami.com/song/playlist/id/' + track.id.slice('xmtrack_'.length) +
'/object_name/default/object_id/0/cat/json';
hm.get(target_url).success(function(data) {
var location = data.data.trackList[0].location;
@ -100,6 +104,7 @@ function xm_bootstrap_track(sound, track, callback, hm, se) {
track.img_url = data.data.trackList[0].pic;
track.album = data.data.trackList[0].album_name;
track.album_id = 'xmalbum_' + data.data.trackList[0].album_id;
track.lyric_url = data.data.trackList[0].lyric_url;
callback();
});
}
@ -115,7 +120,8 @@ function xm_convert_song(song_info, artist_field_name) {
'source': 'xiami',
'source_url': 'http://www.xiami.com/song/' + song_info.song_id,
'img_url': song_info.album_logo,
'url': 'xmtrack_' + song_info.song_id
'url': 'xmtrack_' + song_info.song_id,
'lyric_url': song_info.lyric_file
};
return track;
}
@ -162,7 +168,8 @@ function xm_album(url, hm, se) {
var info = {
'cover_img_url': xm_retina_url(data.data.album_logo),
'title': data.data.album_name,
'id': 'xmalbum_' + data.data.album_id
'id': 'xmalbum_' + data.data.album_id,
'source_url': 'http://www.xiami.com/album/' + data.data.album_id
};
var tracks = [];
@ -197,7 +204,8 @@ function xm_artist(url, hm, se) {
var info = {
'cover_img_url': xm_retina_url(data.data.logo),
'title': data.data.artist_name,
'id': 'xmartist_' + artist_id
'id': 'xmartist_' + artist_id,
'source_url': 'http://www.xiami.com/artist/' + artist_id
};
target_url = 'http://api.xiami.com/web?v=2.0&app_key=1&id=' + artist_id +
@ -211,8 +219,6 @@ function xm_artist(url, hm, se) {
data = data.slice('jsonp217('.length, -')'.length);
data = JSON.parse(data);
var tracks = [];
$.each(data.data, function(index, item){
var track = xm_convert_song(item, 'singers');
@ -223,4 +229,21 @@ function xm_artist(url, hm, se) {
});
}
};
}
}
function xm_lyric(url, hm, se) {
var track_id = getParameterByName('track_id', url).split('_').pop();
var lyric_url = getParameterByName('lyric_url', url);
return {
success: function(fn) {
hm({
url: lyric_url,
method: 'GET',
transformResponse: undefined
}).success(function(data) {
return fn({"lyric":data});
});
}
};
}

View File

@ -179,7 +179,7 @@
<div class="detail-tools">
<a title="添加到当前播放" class="detail-add-button" add-without-play="song" ng-show="options"></a>
<!-- <a title="添加到歌单" class="detail-fav-button" ng-show="options" ng-click="showDialog(0, song)"></a> -->
<a title="原始链接" class="source-button" open-song-source="song" ng-show="options"></a>
<a title="原始链接" class="source-button" open-url="song.source_url" ng-show="options"></a>
</div>
</li>
</ul>
@ -210,7 +210,7 @@
<!-- track list window -->
<div class="site-wrapper" ng-hide="is_window_hidden==1" ng-controller="PlayController">
<div class="site-wrapper" ng-hide="is_window_hidden==1">
<div class="site-wrapper-innerd" resize>
<div class="cover-container" >
@ -225,7 +225,9 @@
</div>
<div class="detail-head-title">
<h2>{{ playlist_title }}</h2>
<a title="播放歌单" class="play" ng-show="playlist_title!=''" ng-click="playmylist(list_id)">播放</a>
<a title="播放歌单" class="play" ng-show="playlist_title!=''" ng-click="playMylist(list_id)">播放</a>
<a title="添加到当前播放" class="add" ng-show="playlist_title!=''" ng-click="addMylist(list_id)">添加到当前播放</a>
<a title="原始链接" class="link" ng-show="playlist_title!=''" open-url="playlist_source_url">原始链接</a>
<!-- <a title="删除歌单" class="delete" ng-show="playlist_title!='' && is_mine=='1'" ng-click="removemylist(list_id)">删除</a>
<a title="收藏歌单" class="clone" ng-show="playlist_title!='' && is_mine=='0'" ng-click="clonelist(list_id)">收藏</a> -->
</div>
@ -238,7 +240,7 @@
<div class="detail-tools">
<a title="添加到当前播放" class="detail-add-button" add-without-play="song" ng-show="options"></a>
<!-- <a title="添加到歌单" class="detail-fav-button" ng-click="showDialog(0, song)" ng-show="options"></a> -->
<a title="原始链接" class="source-button" open-song-source="song" ng-show="options"></a>
<a title="原始链接" class="source-button" open-url="song.source_url" ng-show="options"></a>
<!-- <a title="从歌单删除" class="detail-delete-button" ng-click="removeSongFromPlaylist(song, list_id)" ng-show="options && is_mine=='1' "></a> -->
</div>
</li>
@ -272,7 +274,7 @@
<a class="" ng-click="showArtist(currentPlaying.artist_id)">{{ currentPlaying.artist }}</a>
</span>
</span>
<a open-song-source="currentPlaying" class="src" title="原始链接"></a>
<a open-url="currentPlaying.source_url" class="src" title="原始链接"></a>
</div>
<div class="m-pbar play" >
@ -308,14 +310,10 @@
</div>
<div class="menu" ng-hide="menuHidden">
<div class="menu-header">播放列表
<a class="remove-all" ng-click="menuHidden=!menuHidden">
<small>关闭</small>
</a>
<a clear-playlist class="remove-all">
<small>(移除所有)</small>
</a>
<div class="menu-header">
<span>播放列表</span>
<a clear-playlist class="remove-all"><small>(移除所有)</small></a>
<a class="close-popup" ng-click="menuHidden=!menuHidden">×</a>
</div>
<ul>
<li id="song{{ song.id }}" ng-repeat="song in playlist" ng-class="{ playing: currentPlaying.id == song.id }" ng-mouseenter="playlist_highlight=true" ng-mouseleave="playlist_highlight=false">
@ -324,6 +322,11 @@
<div class="singer" ng-click="showArtist(song.artist_id)">{{ song.artist }}</div>
</li>
</ul>
<div class="lyric">
<div class="placeholder"></div>
<p ng-repeat="line in lyricArray track by $index" ng-class="{ 'highlight': line.lineNumber == lyricLineNumber }" >{{ line.content }} </p>
<div style="placeholder"></div>
</div>
</div>
</div>
</div>