kopia lustrzana https://github.com/friendica/friendica
				
				
				
			Issue 14223: Fix Youtube preview problems
							rodzic
							
								
									aff917a9a8
								
							
						
					
					
						commit
						5873ff7c0e
					
				|  | @ -46,6 +46,7 @@ | |||
| 		"michelf/php-markdown": "^1.7", | ||||
| 		"minishlink/web-push": "^6.0", | ||||
| 		"mobiledetect/mobiledetectlib": "^3.74", | ||||
| 		"mpratt/embera": "~2.0", | ||||
| 		"nikic/fast-route": "^1.3", | ||||
| 		"npm-asset/chart.js": "^2.8", | ||||
| 		"npm-asset/cropperjs": "1.2.2", | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
|         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", | ||||
|         "This file is @generated automatically" | ||||
|     ], | ||||
|     "content-hash": "e93a8ac7e31cf3e5e0ca76134e5ffa0b", | ||||
|     "content-hash": "4dc343e8c8b0edf62a64b2e285fce26f", | ||||
|     "packages": [ | ||||
|         { | ||||
|             "name": "asika/simple-console", | ||||
|  | @ -1771,6 +1771,77 @@ | |||
|             ], | ||||
|             "time": "2023-10-27T16:28:04+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "mpratt/embera", | ||||
|             "version": "2.0.42", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/mpratt/Embera.git", | ||||
|                 "reference": "afa728339c6f078c803c9277a5054ca241b3c469" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/mpratt/Embera/zipball/afa728339c6f078c803c9277a5054ca241b3c469", | ||||
|                 "reference": "afa728339c6f078c803c9277a5054ca241b3c469", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "ext-json": "*", | ||||
|                 "php": ">=5.6" | ||||
|             }, | ||||
|             "require-dev": { | ||||
|                 "phpstan/phpstan": "^1.4", | ||||
|                 "phpunit/phpunit": "^9.0||^10.0", | ||||
|                 "symfony/yaml": "^2.1" | ||||
|             }, | ||||
|             "suggest": { | ||||
|                 "ext-curl": "Fetch data using curl instead of using file_get_contents" | ||||
|             }, | ||||
|             "type": "library", | ||||
|             "autoload": { | ||||
|                 "psr-4": { | ||||
|                     "Embera\\": "src/Embera" | ||||
|                 } | ||||
|             }, | ||||
|             "notification-url": "https://packagist.org/downloads/", | ||||
|             "license": [ | ||||
|                 "MIT" | ||||
|             ], | ||||
|             "authors": [ | ||||
|                 { | ||||
|                     "name": "Michael Pratt", | ||||
|                     "email": "yo@michael-pratt.com", | ||||
|                     "homepage": "http://www.michael-pratt.com", | ||||
|                     "role": "Author/Developer" | ||||
|                 } | ||||
|             ], | ||||
|             "description": "Oembed consumer library. Converts urls into their html embed code. Supports 150+ sites, such as Youtube, Twitter, vimeo, Instagram etc.", | ||||
|             "homepage": "https://github.com/mpratt/Embera", | ||||
|             "keywords": [ | ||||
|                 "Auto embed", | ||||
|                 "Embed Text", | ||||
|                 "Responsive Embeds", | ||||
|                 "Url Embed", | ||||
|                 "embed", | ||||
|                 "instagram", | ||||
|                 "oembed", | ||||
|                 "twitter", | ||||
|                 "vimeo", | ||||
|                 "vine", | ||||
|                 "youtube" | ||||
|             ], | ||||
|             "support": { | ||||
|                 "issues": "https://github.com/mpratt/Embera/issues", | ||||
|                 "source": "https://github.com/mpratt/Embera/tree/2.0.42" | ||||
|             }, | ||||
|             "funding": [ | ||||
|                 { | ||||
|                     "url": "https://paypal.me/mtpratt", | ||||
|                     "type": "paypal" | ||||
|                 } | ||||
|             ], | ||||
|             "time": "2025-01-04T06:07:59+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "nikic/fast-route", | ||||
|             "version": "v1.3.0", | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ namespace Friendica\Util; | |||
| 
 | ||||
| use DOMDocument; | ||||
| use DOMXPath; | ||||
| use DOMElement; | ||||
| use Friendica\Content\Text\HTML; | ||||
| use Friendica\Protocol\HTTP\MediaType; | ||||
| use Friendica\Core\Hook; | ||||
|  | @ -19,6 +20,7 @@ use Friendica\Network\HTTPClient\Client\HttpClientAccept; | |||
| use Friendica\Network\HTTPException; | ||||
| use Friendica\Network\HTTPClient\Client\HttpClientOptions; | ||||
| use Friendica\Network\HTTPClient\Client\HttpClientRequest; | ||||
| use Embera\Embera; | ||||
| 
 | ||||
| /** | ||||
|  * Get information about a given URL | ||||
|  | @ -449,6 +451,10 @@ class ParseUrl | |||
| 					case 'og:type': | ||||
| 						$siteinfo['pagetype'] = trim($meta_tag['content']); | ||||
| 						break; | ||||
| 					case 'og:video': | ||||
| 					case 'og:video:secure_url': | ||||
| 						$siteinfo['player']['embed'] = trim($meta_tag['content']); | ||||
| 						break; | ||||
| 					case 'twitter:description': | ||||
| 						$siteinfo['text'] = trim($meta_tag['content']); | ||||
| 						break; | ||||
|  | @ -458,10 +464,21 @@ class ParseUrl | |||
| 					case 'twitter:image': | ||||
| 						$siteinfo['image'] = $meta_tag['content']; | ||||
| 						break; | ||||
| 					case 'twitter:player': | ||||
| 						$siteinfo['player']['embed'] = trim($meta_tag['content']); | ||||
| 						break; | ||||
| 					case 'twitter:player:width': | ||||
| 						$siteinfo['player']['width'] = intval($meta_tag['content']); | ||||
| 						break; | ||||
| 					case 'twitter:player:height': | ||||
| 						$siteinfo['player']['height'] = intval($meta_tag['content']); | ||||
| 						break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		$siteinfo = self::getOembedInfo($xpath, $siteinfo); | ||||
| 
 | ||||
| 		$list = $xpath->query("//script[@type='application/ld+json']"); | ||||
| 		foreach ($list as $node) { | ||||
| 			if (!empty($node->nodeValue)) { | ||||
|  | @ -1232,6 +1249,21 @@ class ParseUrl | |||
| 			$media['width'] = trim($content); | ||||
| 		} | ||||
| 
 | ||||
| 		$content = JsonLD::fetchElement($jsonld, 'duration'); | ||||
| 		if (!empty($content) && is_string($content)) { | ||||
| 			$media['duration'] = trim($content); | ||||
| 		} | ||||
| 
 | ||||
| 		$content = JsonLD::fetchElement($jsonld, 'contentSize'); | ||||
| 		if (!empty($content) && is_string($content)) { | ||||
| 			$media['size'] = trim($content); | ||||
| 		} | ||||
| 
 | ||||
| 		$content = JsonLD::fetchElement($jsonld, 'uploadDate'); | ||||
| 		if (!empty($content) && is_string($content)) { | ||||
| 			$media['uploaded'] = trim($content); | ||||
| 		} | ||||
| 
 | ||||
| 		$content = JsonLD::fetchElement($jsonld, 'image'); | ||||
| 		if (!empty($content) && is_string($content)) { | ||||
| 			$media['image'] = trim($content); | ||||
|  | @ -1250,4 +1282,143 @@ class ParseUrl | |||
| 		$siteinfo[$name][] = $media; | ||||
| 		return $siteinfo; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Fetch additional information via oEmbed | ||||
| 	 * | ||||
| 	 * @param DOMXPath $xpath | ||||
| 	 * @param array    $siteinfo | ||||
| 	 * | ||||
| 	 * @return array siteinfo | ||||
| 	 */ | ||||
| 	private static function getOembedInfo(DOMXPath $xpath, array $siteinfo): array | ||||
| 	{ | ||||
| 		$oembed = ''; | ||||
| 		foreach ($xpath->query("//link[@type='application/json+oembed']") as $link) { | ||||
| 			/** @var DOMElement $link */ | ||||
| 			$href   = $link->getAttributeNode('href')->nodeValue; | ||||
| 			$oembed = $href; | ||||
| 			DI::logger()->debug('Found oEmbed JSON', ['url' => $href]); | ||||
| 		} | ||||
| 
 | ||||
| 		if (empty($oembed)) { | ||||
| 			$embera  = new Embera(); | ||||
| 			$urldata = $embera->getUrlData([$siteinfo['url']]); | ||||
| 			if (empty($urldata)) { | ||||
| 				return $siteinfo; | ||||
| 			} | ||||
| 			$data = current($urldata); | ||||
| 			DI::logger()->debug('Found oEmbed JSON from Embera', ['url' => $siteinfo['url']]); | ||||
| 		} else { | ||||
| 			$result = DI::httpClient()->get($oembed, HttpClientAccept::DEFAULT, [HttpClientOptions::REQUEST => HttpClientRequest::SITEINFO]); | ||||
| 			if (!$result->isSuccess()) { | ||||
| 				return $siteinfo; | ||||
| 			} | ||||
| 			$json_string = $result->getBodyString(); | ||||
| 			if (empty($json_string)) { | ||||
| 				return $siteinfo; | ||||
| 			} | ||||
| 
 | ||||
| 			$data = json_decode($json_string, true); | ||||
| 		} | ||||
| 
 | ||||
| 		if (empty($data) || !is_array($data)) { | ||||
| 			return $siteinfo; | ||||
| 		} | ||||
| 
 | ||||
| 		// Youtube provides only basic information to some IP ranges.
 | ||||
| 		// We can detect this by checking if the host is youtube.com and if there is no player information.
 | ||||
| 		// In this case we remove all tainted information provided by Youtube and use the ones provided by OEmbed.
 | ||||
| 		if (parse_url(Strings::normaliseLink($siteinfo['url']), PHP_URL_HOST) == 'youtube.com') { | ||||
| 			if (empty($siteinfo['player'])) { | ||||
| 				$fields = ['keywords', 'text', 'title', 'author_name', 'author_url', 'publisher_name', 'publisher_url', 'image']; | ||||
| 				foreach ($fields as $field) { | ||||
| 					unset($siteinfo[$field]); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		$fields = [ | ||||
| 			'title'          => 'title', | ||||
| 			'author_name'    => 'author_name', | ||||
| 			'author_url'     => 'author_url', | ||||
| 			'publisher_name' => 'provider_name', | ||||
| 			'publisher_url'  => 'provider_url', | ||||
| 			'image'          => 'thumbnail_url', | ||||
| 		]; | ||||
| 
 | ||||
| 		foreach ($fields as $key => $value) { | ||||
| 			if (empty($siteinfo[$key]) && !empty($data[$value])) { | ||||
| 				$siteinfo[$key] = $data[$value]; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (!empty($data['html']) && empty($siteinfo['player'])) { | ||||
| 			$siteinfo = self::setPlayer($data['html'], $siteinfo); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!empty($siteinfo['player'])) { | ||||
| 			$fields = [ | ||||
| 				'width'  => 'width', | ||||
| 				'height' => 'height', | ||||
| 			]; | ||||
| 			foreach ($fields as $key => $value) { | ||||
| 				if (empty($siteinfo['player'][$key]) && !empty($data[$value])) { | ||||
| 					$siteinfo['player'][$key] = $data[$value]; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return $siteinfo; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set the player information from the oEmbed HTML in case that it contains an iframe | ||||
| 	 * | ||||
| 	 * @param string $html | ||||
| 	 * @param array  $siteinfo | ||||
| 	 * | ||||
| 	 * @return array siteinfo | ||||
| 	 */ | ||||
| 	private static function setPlayer(String $html, array $siteinfo): array | ||||
| 	{ | ||||
| 		$dom = new DOMDocument(); | ||||
| 		if (!@$dom->loadHTML($html)) { | ||||
| 			return $siteinfo; | ||||
| 		} | ||||
| 
 | ||||
| 		$xpath = new DOMXPath($dom); | ||||
| 
 | ||||
| 		$nodes = $xpath->query('/html/body/*'); | ||||
| 		if ($nodes->length !== 1) { | ||||
| 			return $siteinfo; | ||||
| 		} | ||||
| 
 | ||||
| 		/** @var DOMElement $iframe */ | ||||
| 		$iframe = $nodes->item(0); | ||||
| 		if ($iframe->nodeName !== 'iframe') { | ||||
| 			return $siteinfo; | ||||
| 		} | ||||
| 
 | ||||
| 		$src = $iframe->getAttributeNode('src')->nodeValue; | ||||
| 		if (empty($src)) { | ||||
| 			return $siteinfo; | ||||
| 		} | ||||
| 
 | ||||
| 		$siteinfo['player']['embed'] = $src; | ||||
| 
 | ||||
| 		$width = $iframe->getAttributeNode('width')->nodeValue ?? null; | ||||
| 		if (!empty($width) && is_numeric($width)) { | ||||
| 			$siteinfo['player']['width'] = $width; | ||||
| 		} | ||||
| 
 | ||||
| 		$height = $iframe->getAttributeNode('height')->nodeValue ?? null; | ||||
| 		if (!empty($height) && is_numeric($height)) { | ||||
| 			$siteinfo['player']['height'] = $height; | ||||
| 		} | ||||
| 
 | ||||
| 		DI::logger()->debug('Found oEmbed iframe', ['embed' => $siteinfo['player']['embed'] ?? '', 'width' => $siteinfo['player']['width'] ?? '', 'height' => $siteinfo['player']['height'] ?? '']); | ||||
| 
 | ||||
| 		return $siteinfo; | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Michael
						Michael