通过分享短链接,解析音频--PHP语言

介绍

QQ音乐或网易云音乐的分享短连接,通过解析html内容,解析出来音频下载地址

说明

1:有IP被封的风险,如有特别需要,请自行配置代理
2:此 demo 简单易懂,如有问题,欢迎留言讨论

代码实现

<?php

namespace xFramework\Plugin\Music;

use xFramework\Plugin\Request\Curl;

class Music {

	public static $wPath = X_ROOT_PATH.'/Cache/Music/wyy/'; #本地网易云音乐的保存路径
	public static $qPath = X_ROOT_PATH.'/Cache/Music/qq/';  #本地QQ音乐的保存路径
	public static $wOutPlayUrl = 'http://music.163.com/song/media/outer/url?';
	public static $wSearchUrl = 'http://music.163.com/api/search/get/web?csrf_token=';
	public static $songDataFormat =  [ #自己构建的返回参数
		'song_id'=>'','title'=>'','img'=>'','song_url'=>'','origin_song_url'=>'','down'=>0, 'singers'=>[], 'album'=>''
	];

	/**
	 * 解析网易云分享音乐url, 短链 示例:http://163cn.tv/Nt4J43
	 */
	public static function getNeteaseSong($htmlContent, $shareUrl, $userId = 0){

		$songs = self::$songDataFormat;

		$res = $htmlContent ? $htmlContent : file_get_contents($shareUrl);
		if (empty($res)) {
			return $songs;
		}
		try{
			$dom = new \DOMDocument();
			$dom->loadHTML($res);
			$script = $dom->getElementsByTagName('script');
			$metas = $dom->getElementsByTagName('meta');
			foreach ($script as $key => $value) {
				$content = $value->textContent;
				if (false !== strpos($content, 'window.REDUX_STATE')) { //从script里解析出来
					$contentArr = explode('window.REDUX_STATE = ', $content);
					$realContent = rtrim(trim($contentArr[1]), ';');
					$songData = json_decode($realContent, true);

					if ($songData) {
						$songs['singers'] = $songData['Song']['ar'] ?? [];
						$songs['title'] = $songData['Song']['name'] ?? '';
						$songs['song_id'] = $songData['Song']['id'] ?? 0;
						$songs['img'] = $songData['Song']['al']['picUrl'] ?? '';
						$songs['song_url'] = self::$wOutPlayUrl.'id='.$songs['song_id'].'.mp3';
						$songs['parse_type'] = 'script';
						$songs['album'] = $songData['Song']['al']['name'] ?? '';
					}
				}
			}
			if (empty($songs['title']) && empty($songs['song_id'])) {//script 解析不出来再去meta里解析
				foreach ($metas as $key => $value) {
					$content = $value->getAttribute('content');
					if ($value->getAttribute('property') == 'og:title') {
						$songs['title'] = $content;
					}
					if ($value->getAttribute('property') == 'og:image') {
						$songs['img'] = $content;
					}
					if ($value->getAttribute('property') == 'og:music:artist') {
						$songs['singers'] = [['name'=>$content]];
					}
					if ($value->getAttribute('property') == 'og:url') {
						$songs['song_url'] = $content;
						$songs['song_id'] = explode('id=', $content)[1] ?? '';
					}
					if ($value->getAttribute('property') == 'og:music:album') {
						$songs['album'] = $content;
					}
				}
				if ($songs['song_id']) {
					$songs['parse_type'] = 'meta';
				}
			}

			if ($songs['song_url']) {
				$headers = self::getUrlInfo($songs['song_url'], 'netease');
				if (!empty($headers)) {
					$urlInfo = parse_url($headers['url']);
					$songs['origin_song_url'] = $songs['song_url'];
					$songs['song_url'] = $headers['url'];
					if ($urlInfo['host'] == 'm10.music.126.net') {//这个要特殊处理,有时会403错误而下载不下来数据
						$songs['song_url'] = $urlInfo['scheme'].'://m11.music.126.net'.$urlInfo['path'];
					}
					if ($songs['parse_type'] == 'meta') {
						$songs['down'] = 1;
					}else{
						if ($headers['content_type'] == 'audio/mpeg' || false !== strpos($headers['content_type'], 'audio')) {
							$songs['down'] = 1;
						}
					}
				}
			}

		}catch(\Expection $e){
			$songs['error_msg'] = $e->getMessage();
		}
		return $songs;
	}

	/**
	 * 根据分享短连接获取到songmid   示例:https://c6.y.qq.com/base/fcgi-bin/u?__=WLAmdz0wQfXi 
	 */
	public static function getQQMusicSong($htmlContent, $shareUrl, $userId = 0){

		$songs = $songs = self::$songDataFormat;

		$res = $htmlContent ? $htmlContent : file_get_contents($shareUrl);
		if (empty($res)) {
			return $songs;
		}
		try{
			$dom = new \DOMDocument();
			$dom->loadHTML($res);
			$scripts = $dom->getElementsByTagName('script');
			
			foreach ($scripts as $key => $value) {
				$content = $value->textContent;
				if (false !== strpos($content, 'window.__ssrFirstPageData__')) {
					$realArr = explode("window.__ssrFirstPageData__", $content);
					$songData = explode(" =", $realArr[1])[1] ?? [];
					if ($songData) {
						$songData = json_decode($songData, true);
						$songs['song_id'] = $songData['songList'][0]['id'] ?? 0;
						$songs['mid'] = $songData['songList'][0]['mid'] ?? 0;
						$songs['title'] = $songData['songList'][0]['title'] ?? '';
						$songs['img'] = $songData['metaData']['image'] ?? '';
						$songs['down'] = $songData['songList'][0]['action']['down'] == true  ? 1 : 0;
						$songs['song_url'] = $songData['songList'][0]['url'] ?? '';
						$songs['singers'] = $songData['songList'][0]['singer'] ?? [];
						$songs['album'] = $songData['songList'][0]['album']['name'] ?? '';
					}
				}
			}
			if ($songs['song_url']) {
				$headers = self::getUrlInfo($songs['song_url'], 'qq');
				if (!empty($headers)) {
					$urlInfo = parse_url($headers['url']);
					$songs['origin_song_url'] = $songs['song_url'];
					$songs['song_url'] = $headers['url'];
					if ($headers['content_type'] == 'audio/mpeg' || false !== strpos($headers['content_type'], 'audio')) {
						$songs['down'] = 1;
					}
				}
			}
			
		}catch(\Expection $e){
			$songs['error_msg'] = $e->getMessage();
		}
		return $songs;
		
	}

	/**
	 * 网易云音乐通过歌曲名或者歌手搜索歌曲列表
	 */
	public static function searchWangyiyunMusic($name){

		$curl = curl_init();
	    $post_data = 'hlpretag=<span class="s-fc7">&hlposttag=</span>&s=' . $name . '&type=1&offset=0&total=true&limit=' . $limit;
	    curl_setopt($curl, CURLOPT_URL, self::$wSearchUrl);
	    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
	    $header = array(
	        'Host: music.163.com',
	        'Origin: http://music.163.com',
	        'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36',
	        'Content-Type: application/x-www-form-urlencoded',
	        'Referer: http://music.163.com/search/',
	    );
	    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
	    curl_setopt($curl, CURLOPT_POST, 1);
	    curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
	    $src = curl_exec($curl);
	    curl_close($curl);
	    return $src;
	}

	/**
	 * 下载音乐
	 */
	public static function download($filePath, $url, $songType){

		$headers = self::getCurlHeaders($url, $songType);
	
		$ch = curl_init(); // 启动一个CURL会话
	    curl_setopt($ch, CURLOPT_URL, $url);
	    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
	    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //从证书中检查SSL加密算法是否存在
	    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
	    $result = curl_exec($ch);
	    //关闭URL请求
	    curl_close($ch); 
		file_put_contents($filePath, $result);
	}

	/**
	 * 解析解析出来的url信息
	 */
	public static function getUrlInfo($url, $type, $timeout = 30) {
		   $urlInfo = [];
		   $headers = self::getCurlHeaders($url, $type);
		   $ch = curl_init();
		   curl_setopt($ch, CURLOPT_URL, $url);
		   curl_setopt($ch, CURLOPT_HEADER, 1);
		   curl_setopt($ch, CURLOPT_HTTP_VERSION, 2);
		   curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
	       curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //从证书中检查SSL加密算法是否存在
		   curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);//允许请求的链接跳转
		   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		   curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
		   curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		   curl_setopt($ch, CURLOPT_USERAGENT, 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36');
		   $content = curl_exec($ch);
		   if(!curl_errno($ch)) {
		     $urlInfo = curl_getinfo($ch);//获取最终请求的url地址
		   }
		   curl_close($ch); 
		   return $urlInfo;
		}

	/**
	 * 获取公共的请求头部信息
	 */
	public static function getCurlHeaders($url, $type){

		$headers = [];
		$headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36';
		$headers[] = 'Accept: application/json, text/plain, */*';
		$headers[] = 'Upgrade-Insecure-Requests: 1';
		$urlInfo = parse_url($url);
		switch ($type) {
			case 'netease':
				if (false !== strpos($urlInfo['host'], 'music.126.net')) {
					$headers[] = 'Host: '.$urlInfo['host'];
					$headers[] = 'Origin: '.$urlInfo['scheme'].'://'.$urlInfo['host'];
				}else{
					$headers[] = 'Host: music.163.com';
					$headers[] = 'Origin: http://music.163.com';
				}
				break;
			case 'qq':
				$headers[] = 'Host: '.$urlInfo['host'];
				$headers[] = 'Origin: '.$urlInfo['scheme'].'://'.$urlInfo['host'];
				break;
			default:
				break;
		}

		return $headers;

	}

	/**
	 * 获取URL的headers信息
	 */
	public static function getUrlHeaders12($url){
		$return = [];
		$url = trim($url);
		if (empty($url)) {
			return $return;
		}
		$content = stream_context_set_default([
            'ssl' => [
                'verify_peer' => false,
                'verify_peer_name' => false,
            ],
            'http'=>[
            	'method'=>'HEAD'
            ]
        ]);
		$headers = get_headers($url,1,$content);
		return $headers;
	}



	/**
	 * 获取歌词
	 */
	public function getLyric($songId, $songType){

		$lricData = '';

		switch ($songType) {
			case 'netease':
				$postData = ['id'=>$songId,'os'=>'linux','lv' => -1,'kv' => -1,'tv' => -1];
				$url = 'http://music.163.com/api/song/lyric';
				break;
			default:
				break;
		}
		if (!empty($url)) {
			$curl = new Curl();
			$result = $curl->curl_request($url, $postData, 'urlencoded', 'POST', self::getCurlHeaders($url, $songType));
			if (isset($result['code']) && $result['code'] == 200) {
				$lricData = $result['lrc']['lyric'] ?? '';
			}
		}
		return $lricData;

	}






	



	
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值