Giter Site home page Giter Site logo

embed's Introduction

Embed

Latest Version on Packagist Total Downloads Monthly Downloads Software License

PHP library to get information from any web page (using oembed, opengraph, twitter-cards, scrapping the html, etc). It's compatible with any web service (youtube, vimeo, flickr, instagram, etc) and has adapters to some sites like (archive.org, github, facebook, etc).

Requirements:

If you need PHP 5.5-7.3 support, use the 3.x version

Online demo

http://oscarotero.com/embed/demo

Video Tutorial

Installation

This package is installable and autoloadable via Composer as embed/embed.

$ composer require embed/embed

Usage

use Embed\Embed;

$embed = new Embed();

//Load any url:
$info = $embed->get('https://www.youtube.com/watch?v=PP1xn5wHtxE');

//Get content info

$info->title; //The page title
$info->description; //The page description
$info->url; //The canonical url
$info->keywords; //The page keywords

$info->image; //The thumbnail or main image

$info->code->html; //The code to embed the image, video, etc
$info->code->width; //The exact width of the embed code (if exists)
$info->code->height; //The exact height of the embed code (if exists)
$info->code->ratio; //The percentage of height / width to emulate the aspect ratio using paddings.

$info->authorName; //The resource author
$info->authorUrl; //The author url

$info->cms; //The cms used
$info->language; //The language of the page
$info->languages; //The alternative languages

$info->providerName; //The provider name of the page (Youtube, Twitter, Instagram, etc)
$info->providerUrl; //The provider url
$info->icon; //The big icon of the site
$info->favicon; //The favicon of the site (an .ico file or a png with up to 32x32px)

$info->publishedTime; //The published time of the resource
$info->license; //The license url of the resource
$info->feeds; //The RSS/Atom feeds

Parallel multiple requests

use Embed\Embed;

$embed = new Embed();

//Load multiple urls asynchronously:
$infos = $embed->getMulti(
    'https://www.youtube.com/watch?v=PP1xn5wHtxE',
    'https://twitter.com/carlosmeixidefl/status/1230894146220625933',
    'https://en.wikipedia.org/wiki/Tordoia',
);

foreach ($infos as $info) {
    echo $info->title;
}

Document

The document is the object that store the html code of the page. You can use it to extract extra info from the html code:

//Get the document object
$document = $info->getDocument();

$document->link('image_src'); //Returns the href of a <link>
$document->getDocument(); //Returns the DOMDocument instance
$html = (string) $document; //Returns the html code

$document->select('.//h1'); //Search

You can perform xpath queries in order to select specific elements. A search always return an instance of a Embed\QueryResult:

//Search the A elements
$result = $document->select('.//a');

//Filter the results
$result->filter(fn ($node) => $node->getAttribute('href'));

$id = $result->str('id'); //Return the id of the first result as string
$text = $result->str(); //Return the content of the first result

$ids = $result->strAll('id'); //Return an array with the ids of all results as string
$texts = $result->strAll(); //Return an array with the content of all results as string

$tabindex = $result->int('tabindex'); //Return the tabindex attribute of the first result as integer
$number = $result->int(); //Return the content of the first result as integer

$href = $result->url('href'); //Return the href attribute of the first result as url (converts relative urls to absolutes)
$url = $result->url(); //Return the content of the first result as url

$node = $result->node(); //Return the first node found (DOMElement)
$nodes = $result->nodes(); //Return all nodes found

Metas

For convenience, the object Metas stores the value of all <meta> elements located in the html, so you can get the values easier. The key of every meta is get from the name, property or itemprop attributes and the value is get from content.

//Get the Metas object
$metas = $info->getMetas();

$metas->all(); //Return all values
$metas->get('og:title'); //Return a key value
$metas->str('og:title'); //Return the value as string (remove html tags)
$metas->html('og:description'); //Return the value as html
$metas->int('og:video:width'); //Return the value as integer
$metas->url('og:url'); //Return the value as full url (converts relative urls to absolutes)

OEmbed

In addition to the html and metas, this library uses oEmbed endpoints to get additional data. You can get this data as following:

//Get the oEmbed object
$oembed = $info->getOEmbed();

$oembed->all(); //Return all raw data
$oembed->get('title'); //Return a key value
$oembed->str('title'); //Return the value as string (remove html tags)
$oembed->html('html'); //Return the value as html
$oembed->int('width'); //Return the value as integer
$oembed->url('url'); //Return the value as full url (converts relative urls to absolutes)

Additional oEmbed parameters (like instagrams hidecaption) can also be provided:

$embed = new Embed();

$result = $embed->get('https://www.instagram.com/p/B_C0wheCa4V/');
$result->setSettings([
    'oembed:query_parameters' => ['hidecaption' => true]
]);
$oembed = $info->getOEmbed();

LinkedData

Another API available by default, used to extract info using the JsonLD schema.

//Get the linkedData object
$ld = $info->getLinkedData();

$ld->all(); //Return all data
$ld->get('name'); //Return a key value
$ld->str('name'); //Return the value as string (remove html tags)
$ld->html('description'); //Return the value as html
$ld->int('width'); //Return the value as integer
$ld->url('url'); //Return the value as full url (converts relative urls to absolutes)

Other APIs

Some sites like Wikipedia or Archive.org provide a custom API that is used to fetch more reliable data. You can get the API object with the method getApi() but note that not all results have this method. The Api object has the same methods than oEmbed:

//Get the API object
$api = $info->getApi();

$api->all(); //Return all raw data
$api->get('title'); //Return a key value
$api->str('title'); //Return the value as string (remove html tags)
$api->html('html'); //Return the value as html
$api->int('width'); //Return the value as integer
$api->url('url'); //Return the value as full url (converts relative urls to absolutes)

Extending Embed

Depending of your needs, you may want to extend this library with extra features or change the way it makes some operations.

PSR

Embed use some PSR standards to be the most interoperable possible:

  • PSR-7 Standard interfaces to represent http requests, responses and uris
  • PSR-17 Standard factories to create PSR-7 objects
  • PSR-18 Standard interface to send a http request and return a response

Embed comes with a CURL client compatible with PSR-18 but you need to install a PSR-7 / PSR-17 library. Here you can see a list of popular libraries and the library can detect automatically 'laminas\diactoros', 'guzzleHttp\psr7', 'slim\psr7', 'nyholm\psr7' and 'sunrise\http' (in this order). If you want to use a different PSR implementation, you can do it in this way:

use Embed\Embed;
use Embed\Http\Crawler;

$client = new CustomHttpClient();
$requestFactory = new CustomRequestFactory();
$uriFactory = new CustomUriFactory();

//The Crawler is responsible for perform http queries
$crawler = new Crawler($client, $requestFactory, $uriFactory);

//Create an embed instance passing the Crawler
$embed = new Embed($crawler);

Adapters

There are some sites with special needs: because they provide public APIs that allows to extract more info (like Wikipedia or Archive.org) or because we need to change how to extract the data in this particular site. For all that cases we have the adapters, that are classes extending the default classes to provide extra functionality.

Before creating an adapter, you need to understand how Embed work: when you execute this code, you get a Extractor class

//Get the Extractor with all info
$info = $embed->get($url);

//The extractor have document and oembed:
$document = $info->getDocument();
$oembed = $info->getOEmbed();

The Extractor class has many Detectors. Each detector is responsible to detect a specific piece of info. For example, there's a detector for the title, other for description, image, code, etc.

So, an adapter is basically an extractor created specifically for a site. It can contains also custom detectors or apis. If you see the src/Adapters folder you can see all adapters.

If you create an adapter, you need also register to Embed, so it knows in which website needs to use. To do that, there's the ExtractorFactory object, that is responsible for instantiate the right extractor for each site.

use Embed\Embed;

$embed = new Embed();

$factory = $embed->getExtractorFactory();

//Use this MySite adapter for mysite.com
$factory->addAdapter('mysite.com', MySite::class);

//Remove the adapter for pinterest.com, so it will use the default extractor
$factory->removeAdapter('pinterest.com');

//Change the default extractor
$factory->setDefault(CustomExtractor::class);

Detectors

Embed comes with several predefined detectors, but you may want to change or add more. Just create a class extending Embed\Detectors\Detector class and register it in the extractor factory. For example:

use Embed\Embed;
use Embed\Detectors\Detector;

class Robots extends Detector
{
    public function detect(): ?string
    {
        $response = $this->extractor->getResponse();
        $metas = $this->extractor->getMetas();

        return $response->getHeaderLine('x-robots-tag'),
            ?: $metas->str('robots');
    }
}

//Register the detector
$embed = new Embed();
$embed->getExtractorFactory()->addDetector('robots', Robots::class);

//Use it
$info = $embed->get('http://example.com');
$robots = $info->robots;

Settings

If you need to pass settings to the CurlClient to perform http queries:

use Embed\Embed;
use Embed\Http\Crawler;
use Embed\Http\CurlClient;

$client = new CurlClient();
$client->setSettings([
    'cookies_path' => $cookies_path,
    'ignored_errors' => [18],
    'max_redirs' => 3,               // see CURLOPT_MAXREDIRS
    'connect_timeout' => 2,          // see CURLOPT_CONNECTTIMEOUT
    'timeout' => 2,                  // see CURLOPT_TIMEOUT
    'ssl_verify_host' => 2,          // see CURLOPT_SSL_VERIFYHOST
    'ssl_verify_peer' => 1,          // see CURLOPT_SSL_VERIFYPEER
    'follow_location' => true,       // see CURLOPT_FOLLOWLOCATION
    'user_agent' => 'Mozilla',       // see CURLOPT_USERAGENT
]);

$embed = new Embed(new Crawler($client));

If you need to pass settings to your detectors, you can add settings to the ExtractorFactory:

use Embed\Embed;

$embed = new Embed();
$embed->setSettings([
    'oembed:query_parameters' => [],  //Extra parameters send to oembed
    'twitch:parent' => 'example.com', //Required to embed twitch videos as iframe
    'facebook:token' => '1234|5678',  //Required to embed content from Facebook
    'instagram:token' => '1234|5678', //Required to embed content from Instagram
    'twitter:token' => 'asdf',        //Improve the data from twitter
]);
$info = $embed->get($url);

Note: The built-in detectors does not require settings. This feature is only for convenience if you create a specific detector that requires settings.


embed's People

Contributors

abetwothree avatar brianlmoon avatar cristianoerardt avatar damienalexandre avatar dieterholvoet avatar digilist avatar dman-coders avatar grandeljay avatar janmisker avatar janpettermg avatar kleiram avatar kmcs avatar mburtscher avatar nerg4l avatar nicolas-t avatar oscarotero avatar patriksh avatar paulhennell avatar raymondelferink avatar rentalhost avatar rjackson avatar sharkmachine avatar soullivaneuh avatar spekulatius avatar szepeviktor avatar thekillerfox avatar xynnn avatar zerolab avatar zobzn avatar zyuhel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

embed's Issues

Autoplay embed code?

Is there an option to set the autoplay property for the embed code.

For example, the YouTube embed code by default looks like this:

<iframe width="480" height="270" src="https://www.youtube.com/embed/jbM9uCxEJDM?feature=oembed" frameborder="0" allowfullscreen></iframe>

Is it possible to add the autoplay parameter, like this:

<iframe width="480" height="270" src="https://www.youtube.com/embed/jbM9uCxEJDM?feature=oembed&autoplay=1" frameborder="0" allowfullscreen></iframe>

Trailing Slashes not working

http://www.domain.com/path/ gets internally resolved to http://www.domain.com/path.

Now, if the server is configured for SEO / DC reasons to generate a 404 response / doc if that trailing slash is missing, Houston has a problem.

one solution would be :

public function setPath ($path) {
        $this->info['path'] = array();

        foreach (explode('/', $path) as $dir) {
            if ($dir !== '') {
                $this->info['path'][] = $dir;
            }
        }
        $this->info['trailingSlash'] = preg_match( '`\/$`', $path );
        $this->buildUrl();
    }

and in buildUrl()

...

if (isset($this->info['fragment'])) {
            $url .= '#'.$this->info['fragment'];
        }

        if( $this->info['trailingSlash'] ) {
            $url .= '/';
        }

        if (!$maintainCache && ($this->url !== $url)) {
            $this->clearCache();
        }
...

Support short domains for rdio

Rdio also allows embedding using short domains.

For example: http://rd.io/x/Q1IjXC8s redirects to http://www.rdio.com/artist/Soundgarden/album/Superunknown/

Problem with google.com.au

Use JSON instead of JS for gists

Currently, gists are embedded using the javascript file: https://gist.github.com/pjhyett/7.js

This results in generated code that looks like:

<script src="https://gist.github.com/pjhyett/7.js"></script>

However, this poses problems when we ask Embed to generate the embed code via ajax and embed it the page using javascript. Because the gist javascript uses document.write() it does not work properly.

Since gist provides a json version: https://gist.github.com/pjhyett/7.json, it would be nice if it can generate the proper embed code instead:

<link href="https://gist-assets.github.com/assets/embed-e8861c84ff85edae1cf9869dd551c98d.css" rel="stylesheet">
<div class="gist" id="gist7">
        <div class="gist-file">
          <div class="gist-data gist-syntax">
    <div class="file-data">
      <table cellspacing="0" cellpadding="0" class="lines highlight">
        <tbody><tr>
          <td class="line-numbers">
            <span rel="file-z2_stog_polje_isantala-L1" id="file-z2_stog_polje_isantala-L1" class="line-number">1</span>
            <span rel="file-z2_stog_polje_isantala-L2" id="file-z2_stog_polje_isantala-L2" class="line-number">2</span>
            <span rel="file-z2_stog_polje_isantala-L3" id="file-z2_stog_polje_isantala-L3" class="line-number">3</span>
            <span rel="file-z2_stog_polje_isantala-L4" id="file-z2_stog_polje_isantala-L4" class="line-number">4</span>
            <span rel="file-z2_stog_polje_isantala-L5" id="file-z2_stog_polje_isantala-L5" class="line-number">5</span>
            <span rel="file-z2_stog_polje_isantala-L6" id="file-z2_stog_polje_isantala-L6" class="line-number">6</span>
            <span rel="file-z2_stog_polje_isantala-L7" id="file-z2_stog_polje_isantala-L7" class="line-number">7</span>
            <span rel="file-z2_stog_polje_isantala-L8" id="file-z2_stog_polje_isantala-L8" class="line-number">8</span>
            <span rel="file-z2_stog_polje_isantala-L9" id="file-z2_stog_polje_isantala-L9" class="line-number">9</span>
            <span rel="file-z2_stog_polje_isantala-L10" id="file-z2_stog_polje_isantala-L10" class="line-number">10</span>
            <span rel="file-z2_stog_polje_isantala-L11" id="file-z2_stog_polje_isantala-L11" class="line-number">11</span>
            <span rel="file-z2_stog_polje_isantala-L12" id="file-z2_stog_polje_isantala-L12" class="line-number">12</span>
            <span rel="file-z2_stog_polje_isantala-L13" id="file-z2_stog_polje_isantala-L13" class="line-number">13</span>
            <span rel="file-z2_stog_polje_isantala-L14" id="file-z2_stog_polje_isantala-L14" class="line-number">14</span>
            <span rel="file-z2_stog_polje_isantala-L15" id="file-z2_stog_polje_isantala-L15" class="line-number">15</span>
            <span rel="file-z2_stog_polje_isantala-L16" id="file-z2_stog_polje_isantala-L16" class="line-number">16</span>
            <span rel="file-z2_stog_polje_isantala-L17" id="file-z2_stog_polje_isantala-L17" class="line-number">17</span>
            <span rel="file-z2_stog_polje_isantala-L18" id="file-z2_stog_polje_isantala-L18" class="line-number">18</span>
            <span rel="file-z2_stog_polje_isantala-L19" id="file-z2_stog_polje_isantala-L19" class="line-number">19</span>
            <span rel="file-z2_stog_polje_isantala-L20" id="file-z2_stog_polje_isantala-L20" class="line-number">20</span>
            <span rel="file-z2_stog_polje_isantala-L21" id="file-z2_stog_polje_isantala-L21" class="line-number">21</span>
            <span rel="file-z2_stog_polje_isantala-L22" id="file-z2_stog_polje_isantala-L22" class="line-number">22</span>
            <span rel="file-z2_stog_polje_isantala-L23" id="file-z2_stog_polje_isantala-L23" class="line-number">23</span>
            <span rel="file-z2_stog_polje_isantala-L24" id="file-z2_stog_polje_isantala-L24" class="line-number">24</span>
            <span rel="file-z2_stog_polje_isantala-L25" id="file-z2_stog_polje_isantala-L25" class="line-number">25</span>
            <span rel="file-z2_stog_polje_isantala-L26" id="file-z2_stog_polje_isantala-L26" class="line-number">26</span>
            <span rel="file-z2_stog_polje_isantala-L27" id="file-z2_stog_polje_isantala-L27" class="line-number">27</span>
            <span rel="file-z2_stog_polje_isantala-L28" id="file-z2_stog_polje_isantala-L28" class="line-number">28</span>
            <span rel="file-z2_stog_polje_isantala-L29" id="file-z2_stog_polje_isantala-L29" class="line-number">29</span>
            <span rel="file-z2_stog_polje_isantala-L30" id="file-z2_stog_polje_isantala-L30" class="line-number">30</span>
            <span rel="file-z2_stog_polje_isantala-L31" id="file-z2_stog_polje_isantala-L31" class="line-number">31</span>
            <span rel="file-z2_stog_polje_isantala-L32" id="file-z2_stog_polje_isantala-L32" class="line-number">32</span>
            <span rel="file-z2_stog_polje_isantala-L33" id="file-z2_stog_polje_isantala-L33" class="line-number">33</span>
            <span rel="file-z2_stog_polje_isantala-L34" id="file-z2_stog_polje_isantala-L34" class="line-number">34</span>
            <span rel="file-z2_stog_polje_isantala-L35" id="file-z2_stog_polje_isantala-L35" class="line-number">35</span>
            <span rel="file-z2_stog_polje_isantala-L36" id="file-z2_stog_polje_isantala-L36" class="line-number">36</span>
            <span rel="file-z2_stog_polje_isantala-L37" id="file-z2_stog_polje_isantala-L37" class="line-number">37</span>
            <span rel="file-z2_stog_polje_isantala-L38" id="file-z2_stog_polje_isantala-L38" class="line-number">38</span>
            <span rel="file-z2_stog_polje_isantala-L39" id="file-z2_stog_polje_isantala-L39" class="line-number">39</span>
            <span rel="file-z2_stog_polje_isantala-L40" id="file-z2_stog_polje_isantala-L40" class="line-number">40</span>
            <span rel="file-z2_stog_polje_isantala-L41" id="file-z2_stog_polje_isantala-L41" class="line-number">41</span>
            <span rel="file-z2_stog_polje_isantala-L42" id="file-z2_stog_polje_isantala-L42" class="line-number">42</span>
            <span rel="file-z2_stog_polje_isantala-L43" id="file-z2_stog_polje_isantala-L43" class="line-number">43</span>
            <span rel="file-z2_stog_polje_isantala-L44" id="file-z2_stog_polje_isantala-L44" class="line-number">44</span>
            <span rel="file-z2_stog_polje_isantala-L45" id="file-z2_stog_polje_isantala-L45" class="line-number">45</span>
            <span rel="file-z2_stog_polje_isantala-L46" id="file-z2_stog_polje_isantala-L46" class="line-number">46</span>
            <span rel="file-z2_stog_polje_isantala-L47" id="file-z2_stog_polje_isantala-L47" class="line-number">47</span>
            <span rel="file-z2_stog_polje_isantala-L48" id="file-z2_stog_polje_isantala-L48" class="line-number">48</span>
            <span rel="file-z2_stog_polje_isantala-L49" id="file-z2_stog_polje_isantala-L49" class="line-number">49</span>
            <span rel="file-z2_stog_polje_isantala-L50" id="file-z2_stog_polje_isantala-L50" class="line-number">50</span>
          </td>
          <td class="line-data">
            <pre class="line-pre"><div id="file-z2_stog_polje_isantala-LC1" class="line">struct tauto {</div><div id="file-z2_stog_polje_isantala-LC2" class="line">   int sb;</div><div id="file-z2_stog_polje_isantala-LC3" class="line">   char pro[30];</div><div id="file-z2_stog_polje_isantala-LC4" class="line">   char mod[30];</div><div id="file-z2_stog_polje_isantala-LC5" class="line">   int god;</div><div id="file-z2_stog_polje_isantala-LC6" class="line">} auto;</div><div id="file-z2_stog_polje_isantala-LC7" class="line">       </div><div id="file-z2_stog_polje_isantala-LC8" class="line">struct stack {</div><div id="file-z2_stog_polje_isantala-LC9" class="line">   int sb[21];</div><div id="file-z2_stog_polje_isantala-LC10" class="line">   char pro[21][30];</div><div id="file-z2_stog_polje_isantala-LC11" class="line">   char mod[21][30];</div><div id="file-z2_stog_polje_isantala-LC12" class="line">   int god[21];</div><div id="file-z2_stog_polje_isantala-LC13" class="line">   int cursor;</div><div id="file-z2_stog_polje_isantala-LC14" class="line">};</div><div id="file-z2_stog_polje_isantala-LC15" class="line">&nbsp;</div><div id="file-z2_stog_polje_isantala-LC16" class="line">tauto TopS (stack* S){</div><div id="file-z2_stog_polje_isantala-LC17" class="line">   if(S-&gt;cursor != 20) {</div><div id="file-z2_stog_polje_isantala-LC18" class="line">     auto.sb = S-&gt;sb[S-&gt;cursor+1];</div><div id="file-z2_stog_polje_isantala-LC19" class="line">     strcpy(auto.pro, S-&gt;pro[S-&gt;cursor+1]);</div><div id="file-z2_stog_polje_isantala-LC20" class="line">     strcpy(auto.mod, S-&gt;mod[S-&gt;cursor+1]);</div><div id="file-z2_stog_polje_isantala-LC21" class="line">     auto.god = S-&gt;god[S-&gt;cursor+1];</div><div id="file-z2_stog_polje_isantala-LC22" class="line">     return auto;</div><div id="file-z2_stog_polje_isantala-LC23" class="line">   }</div><div id="file-z2_stog_polje_isantala-LC24" class="line">}</div><div id="file-z2_stog_polje_isantala-LC25" class="line">&nbsp;</div><div id="file-z2_stog_polje_isantala-LC26" class="line">void PushS (tauto x, stack* S){</div><div id="file-z2_stog_polje_isantala-LC27" class="line">  if(S-&gt;cursor&gt;=0) {</div><div id="file-z2_stog_polje_isantala-LC28" class="line">   S-&gt;sb[S-&gt;cursor] = x.sb;</div><div id="file-z2_stog_polje_isantala-LC29" class="line">   strcpy(S-&gt;pro[S-&gt;cursor], x.pro); </div><div id="file-z2_stog_polje_isantala-LC30" class="line">   strcpy(S-&gt;mod[S-&gt;cursor], x.mod); </div><div id="file-z2_stog_polje_isantala-LC31" class="line">   S-&gt;god[S-&gt;cursor] = x.god;</div><div id="file-z2_stog_polje_isantala-LC32" class="line">   S-&gt;cursor--;</div><div id="file-z2_stog_polje_isantala-LC33" class="line">  }</div><div id="file-z2_stog_polje_isantala-LC34" class="line">}</div><div id="file-z2_stog_polje_isantala-LC35" class="line">&nbsp;</div><div id="file-z2_stog_polje_isantala-LC36" class="line">void PopS (stack* S) {</div><div id="file-z2_stog_polje_isantala-LC37" class="line">   if (S-&gt;cursor &lt;= 20)</div><div id="file-z2_stog_polje_isantala-LC38" class="line">     S-&gt;cursor++;</div><div id="file-z2_stog_polje_isantala-LC39" class="line">}</div><div id="file-z2_stog_polje_isantala-LC40" class="line">&nbsp;</div><div id="file-z2_stog_polje_isantala-LC41" class="line">stack* InitS (stack* S) {</div><div id="file-z2_stog_polje_isantala-LC42" class="line">   S = new stack;</div><div id="file-z2_stog_polje_isantala-LC43" class="line">   S -&gt; cursor = 20;</div><div id="file-z2_stog_polje_isantala-LC44" class="line">   return S;</div><div id="file-z2_stog_polje_isantala-LC45" class="line">} </div><div id="file-z2_stog_polje_isantala-LC46" class="line">&nbsp;</div><div id="file-z2_stog_polje_isantala-LC47" class="line">bool IsEmptyS (stack* S) {</div><div id="file-z2_stog_polje_isantala-LC48" class="line">   if (S-&gt;cursor == 20) return 1;</div><div id="file-z2_stog_polje_isantala-LC49" class="line">   else return 0;     </div><div id="file-z2_stog_polje_isantala-LC50" class="line">}   </div></pre>
          </td>
        </tr>
      </tbody></table>
    </div>

          </div>
          <div class="gist-meta">
            <a style="float:right" href="https://gist.github.com/pjhyett/7/raw/Z2_stog_polje_isantala">view raw</a>
            <a href="https://gist.github.com/pjhyett/7#file-z2_stog_polje_isantala">Z2_stog_polje_isantala</a>
            hosted with ❤ by <a href="https://github.com">GitHub</a>
          </div>
        </div>
</div>

Facebook Embeds default language

Currently, embeds are set to use gl_ES by default. However, I think it would be better to set it to en_US by default, and provide a configuration option for users to set their own language.

In addition, the script tag's contents appear to have been updated:

<div id="fb-root"></div>
<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.0";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>

Wrong type when embedding gists

Custom get parameters

I would love to have some where to pass in custom get parameters.

For example, the twitter oembed api contains some extra get parameters such as omit_script: https://dev.twitter.com/docs/api/1/get/statuses/oembed

Maybe the options array passed to create can have an extra parameters element:

$options = array(
    'parameters' => array('omit_script' => true) 
);

oEmbed responses with type 'photo' confuse the web page adapter about "canonical" url.

When Embed is working with a URL with an oEmbed response of type photo, this response URL will confuse the adapter constructor into thinking the image's URL is the canonical URL for the requested resource.

If you test with http://www.flickr.com/photos/boris/2351723120 you can see the problem. Instead of all the details of the Flickr image including the author name and a thumbnail maybe, I am given just the image http://farm4.staticflickr.com/3209/2351723120_bd2d45a3cc_b.jpg that was referenced in the oEmbed response.

http://oscarotero.com/embed/test.php?url=http%3A%2F%2Fwww.flickr.com%2Fphotos%2Fboris%2F2351723120

Class Embed\Embed not found

I try to use your library from a standard symfony project and I get this error:

PHP Fatal error:  Class 'Embed\Embed' not found in /home/sullivan/projects/ddn/src/AppBundle/Manager/PressSourceManager.php on line 104
PHP Stack trace:
PHP   1. {main}() /home/sullivan/projects/ddn/app/console:0
PHP   2. Symfony\Component\Console\Application->run() /home/sullivan/projects/ddn/app/console:27
PHP   3. Symfony\Bundle\FrameworkBundle\Console\Application->doRun() /home/sullivan/projects/ddn/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:126
PHP   4. Symfony\Component\Console\Application->doRun() /home/sullivan/projects/ddn/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php:96
PHP   5. Symfony\Component\Console\Application->doRunCommand() /home/sullivan/projects/ddn/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:195
PHP   6. Symfony\Component\Console\Command\Command->run() /home/sullivan/projects/ddn/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:882
PHP   7. AppBundle\Command\PressFetchCommand->execute() /home/sullivan/projects/ddn/vendor/symfony/symfony/src/Symfony/Component/Console/Command/Command.php:252
PHP   8. AppBundle\Manager\PressSourceManager->refreshSource() /home/sullivan/projects/ddn/src/AppBundle/Command/PressFetchCommand.php:32
PHP   9. AppBundle\Manager\PressSourceManager->generateArticleFromItem() /home/sullivan/projects/ddn/src/AppBundle/Manager/PressSourceManager.php:60

Fatal error: Class 'Embed\Embed' not found in /home/sullivan/projects/ddn/src/AppBundle/Manager/PressSourceManager.php on line 104

Call Stack:
    0.0001     240208   1. {main}() /home/sullivan/projects/ddn/app/console:0
    0.0264    3318376   2. Symfony\Component\Console\Application->run() /home/sullivan/projects/ddn/app/console:27
    0.0288    3521488   3. Symfony\Bundle\FrameworkBundle\Console\Application->doRun() /home/sullivan/projects/ddn/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:126
    0.1865   15620192   4. Symfony\Component\Console\Application->doRun() /home/sullivan/projects/ddn/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php:96
    0.1867   15621112   5. Symfony\Component\Console\Application->doRunCommand() /home/sullivan/projects/ddn/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:195
    0.1932   15812784   6. Symfony\Component\Console\Command\Command->run() /home/sullivan/projects/ddn/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php:882
    0.1934   15817176   7. AppBundle\Command\PressFetchCommand->execute() /home/sullivan/projects/ddn/vendor/symfony/symfony/src/Symfony/Component/Console/Command/Command.php:252
    0.3071   24171424   8. AppBundle\Manager\PressSourceManager->refreshSource() /home/sullivan/projects/ddn/src/AppBundle/Command/PressFetchCommand.php:32
    1.1834   24244152   9. AppBundle\Manager\PressSourceManager->generateArticleFromItem() /home/sullivan/projects/ddn/src/AppBundle/Manager/PressSourceManager.php:60

  [Symfony\Component\Debug\Exception\ClassNotFoundException]                                
  Attempted to load class "Embed" from namespace "Embed".                                   
  Did you forget a "use" statement for e.g. "Twig_Node_Embed" or "Twig_TokenParser_Embed"?  

I think it's an auto-load error after comparing between your installed package and an another:

$ composer show embed/embed
name     : embed/embed                                                                       
descrip. : PHP library to retrieve page info using oembed, opengraph, etc
keywords : embed, embedly, oembed, opengraph, twitter cards
versions : dev-master, * v1.8.0, v1.7.0, v1.6.0, v1.5.9, v1.5.8, v1.5.7, v1.5.6, v1.5.5, v1.5.4, v1.5.3, v1.5.2, v1.5.1, v1.5.0, v1.4.6, v1.4.5, v1.4.4, v1.4.3, 1.4.2, v1.4.1, v1.4.0, v1.3.8, v1.3.7, v1.3.6, v1.3.5, v1.3.4, v1.3.3, v1.3.2, v1.3.1, v1.3.0, v1.2.1, v1.2.0, v1.1.1, v1.1.0, v1.0.2, v1.0.1, dev-changes, dev-custom_urls_resolvers
type     : library
license  : MIT
source   : [git] https://github.com/oscarotero/Embed.git 7a2720901652f5e2e3df9609648718573d60aae1
dist     : [zip] https://api.github.com/repos/oscarotero/Embed/zipball/7a2720901652f5e2e3df9609648718573d60aae1 7a2720901652f5e2e3df9609648718573d60aae1
names    : embed/embed

autoload
psr-0
Embed => .

requires
php >=5.3.0
$ composer show guzzlehttp/guzzle
name     : guzzlehttp/guzzle                                                                 
descrip. : Guzzle is a PHP HTTP client library and framework for building RESTful web service clients
keywords : client, curl, framework, http, http client, rest, web service
versions : dev-master, 5.0.x-dev, 5.0.3, 5.0.2, 5.0.1, 5.0.0, * 4.2.3, 4.2.2, 4.2.1, 4.2.0, 4.1.8, 4.1.7, 4.1.6, 4.1.5, 4.1.4, 4.1.3, 4.1.2, 4.1.1, 4.1.0, 4.0.2, 4.0.1, 4.0.0, 4.0.0-rc.2, 4.0.0-rc.1, v3.8.1, v3.8.0, v3.7.4, v3.7.3, v3.7.2, v3.7.1, v3.7.0, v3.6.0, v3.5.0, v3.4.3, v3.4.2, v3.4.1, v3.4.0, v3.3.1, v3.3.0, v3.2.0, v3.1.2, v3.1.1, v3.1.0, v3.0.7, v3.0.6, v3.0.5, v3.0.4, v3.0.3, v3.0.2, v3.0.1, v3.0.0, v2.8.8, v2.8.7, v2.8.6, v2.8.5, v2.8.4, v2.8.3, v2.8.2, v2.8.1, v2.8.0, v2.7.2, v2.7.1, v2.7.0, v2.6.6, v2.6.5, v2.6.4, v2.6.3, v2.6.2, v2.6.1, v2.6.0, v2.5.0, v2.4.1, v2.4.0, v2.3.2, v2.2.4, v2.2.3, v2.2.2, v2.2.1, v2.2.0, v2.1.4, v2.1.3, v2.1.2, v2.1.1, v2.1.0, v2.0.5, v2.0.4, v2.0.3, v2.0.2, v2.0.1, v2.0.0, v1.0.4, v1.0.3, dev-null_override
type     : library
license  : MIT
source   : [git] https://github.com/guzzle/guzzle.git 66fd916e9f9130bc22c51450476823391cb2f67c
dist     : [zip] https://api.github.com/repos/guzzle/guzzle/zipball/66fd916e9f9130bc22c51450476823391cb2f67c 66fd916e9f9130bc22c51450476823391cb2f67c
names    : guzzlehttp/guzzle

autoload
psr-4
GuzzleHttp\ => src/
files

As you can see, the autoload configuration is different. But I don't know if is relevant.

Here, an extract of my php code using your class:

use Embed\Embed;

// [...]
    private function generateArticleFromItem(Item $item)
    {
        $article = new PressArticle();
        $embed = Embed::create($articleUrl);
        $article->setIntroduction($embed->getDescription());

        return $article;
    }
// [...]

And my full composer.json file:

{
    "name": "ddn/ddn",
    "type": "project",
    "autoload": {
        "psr-0": { "": "src/", "SymfonyStandard": "app/" }
    },
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/Soullivaneuh/SonataDoctrineORMAdminBundle.git"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "ext-gd": "*",
        "symfony/symfony": "2.6.*",
        "doctrine/orm": "~2.2,>=2.2.3",
        "doctrine/doctrine-bundle": "~1.2",
        "doctrine/mongodb-odm-bundle": "3.0.*",
        "doctrine/migrations" : "dev-master",
        "doctrine/doctrine-migrations-bundle": "dev-master",
        "stof/doctrine-extensions-bundle": "~1.1",
        "twig/extensions": "~1.1",
        "symfony/assetic-bundle": "~2.3",
        "symfony/swiftmailer-bundle": "~2.3",
        "symfony/monolog-bundle": "~2.4",
        "sensio/distribution-bundle": "~3.0",
        "sensio/framework-extra-bundle": "~3.0",
        "incenteev/composer-parameter-handler": "~2.0",
        "mopa/bootstrap-bundle": "3.x-dev",
        "knplabs/knp-paginator-bundle": "2.4.*",
        "knplabs/knp-menu-bundle": "2.0.*",
        "craue/formflow-bundle": "2.1.*",
        "friendsofsymfony/user-bundle": "2.0.x-dev",
        "friendsofsymfony/oauth-server-bundle": "1.4.*",
        "friendsofsymfony/rest-bundle": "1.4.*",
        "sonata-project/admin-bundle": "~2.3",
        "sonata-project/doctrine-orm-admin-bundle": "dev-list-builder-template",
        "sonata-project/intl-bundle": "~2.2",
        "jms/serializer-bundle": "~0.13",
        "ornicar/gravatar-bundle": "~1.1",
        "aferrandini/urlizer": "1.0.*",
        "guzzlehttp/guzzle": "~4.0",
        "vich/uploader-bundle": "~0.11",
        "gregwar/image-bundle": "~2.0",
        "kriswallsmith/spork": "~0.2",
        "inlinestyle/inlinestyle": "*",
        "debril/rss-atom-bundle": "~1.4",
        "fabpot/goutte": "~2.0",
        "embed/embed": "~1.8"
    },
    "require-dev": {
        "sonata-project/easy-extends-bundle": "~2.1",
        "sensio/generator-bundle": "~2.4",
        "squizlabs/php_codesniffer": "~1.5",
        "fabpot/php-cs-fixer": "*",
        "sebastian/phpcpd": "~2.0",
        "phpspec/phpspec": "~2.0",
        "henrikbjorn/phpspec-code-coverage": "~0.2",
        "behat/behat": "~3.0",
        "behat/symfony2-extension": "~2.0",
        "behat/mink-extension": "~2.0",
        "behat/mink-browserkit-driver": "~1.2"
    },
    "scripts": {
        "post-root-package-install": [
            "SymfonyStandard\\Composer::hookRootPackageInstall"
        ],
        "post-install-cmd": [
            "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::removeSymfonyStandardFiles"
        ],
        "post-update-cmd": [
            "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
            "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::removeSymfonyStandardFiles"
        ]
    },
    "config": {
        "bin-dir": "bin"
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "extra": {
        "symfony-app-dir": "app",
        "symfony-web-dir": "web",
        "symfony-assets-install": "relative",
        "incenteev-parameters": {
            "file": "app/config/parameters.yml"
        },
        "branch-alias": {
            "dev-master": "2.6-dev"
        }
    }
}

Ask me if you want more information.

Thanks!

More permissive license

The current AGPL license is really restrictive. Projects that could benefit from this library might not be able to use it because of legal reasons.

I understand you might want to reserve some right, making a license like BSD or MIT to permissive. Please consider using something like CC BY-SA 3.0 or LGPL.

Thanks for making the world a better place!

SoundCloud clips with no artwork causes error

Hi

I found that embedding Soundcloud clips without artwork causes an error -

Example clip: https://soundcloud.com/ididthat-1/lowe-ct-cape-times-world-cup

Error
vendor/embed/embed/src/Adapters/Soundcloud.php(89): Embed\Utils::unshiftValue(Array, Array)

'Illegal offset type' in vendor/embed/embed/src/Utils.php:135

Note, when I comment out the following section in Adapters/Soundcloud.php
line: 85 - 90

/*
        if (!$this->api->get('artwork_url') && ($img = $this->api->get('user', 'avatar_url'))) {
            Utils::unshiftValue($images, [
                'value' => str_replace('-large.jpg', '-t500x500.jpg', $img),
                'providers' => ['api'],
            ]);
        }
*/

The clip renders perfect, with the Avatar as clip's artwork.

Remove demo code from library?

If I were to download this library and put it in a web-accessible location, I would feel uneasy knowing that people can easily hit the test.php or test-sources.php files on my server. Would it be possible to exclude these files from repository but still leave them on the demo site?

Mashable articles coming back with type of photo

aspectRatio returns null if we don't access width and height first

To reproduce:

<?php
require ('embed/src/autoloader.php');

$info = Embed\Embed::create('https://www.youtube.com/watch?v=dd7sV6SAEAU');
//var_dump($info->width);
//var_dump($info->height);
var_dump($info->aspectRatio);

Notice that aspectRatio returns null. However, if we uncomment the 2 var_dumps for width and height, apectRatio returns a value.

Tested with PHP 5.6.7 and 5.6.8

SoundCloud: Get user image if no artwork exists

The soundcloud website will show the user image for a track, if the track doesn't have an artwork image. See https://soundcloud.com/djsaber/dj-saber-souldelight-late-night-freakin

The OEmbed response will give a general placeholder image instead. Which just isn't nice. I'd prefer if the Embed library would return the user's image instead.

The library could use the API to fetch this image and more data:
http://api.soundcloud.com/resolve.json?url=https://soundcloud.com/djsaber/dj-saber-souldelight-late-night-freakin&client_id=YOUR_CLIENT_ID

Note: YOUR_CLIENT_ID is actually valid, so you don't need to register an application to get this data.

Better description detection

Argument 1 passed to Embed\Providers\Html::extractImages() must be an instance of DOMElement, null given

Catchable fatal error: Argument 1 passed to Embed\Providers\Html::extractImages() must be an instance of DOMElement, null given, called in /var/www/vhosts/oscarotero.com/httpdocs/embed2/src/Providers/Html.php on line 33 and defined in /var/www/vhosts/oscarotero.com/httpdocs/embed2/src/Providers/Html.php on line 237

for example:

http://oscarotero.com/embed2/demo/index.php?url=http%3A%2F%2Fblogs.wsj.com%2Fdigits%2F2015%2F05%2F08%2Famazons-prices-often-undercut-by-upstart-jet-com-study-finds%2F

Probably has to do with the WSJ paywall?

Giving false

When I try to fetch embed of a YouTube url, It gives false.

Here is my code:

    error_reporting(E_ALL);
    ini_set('display_errors', 1);

    $url = 'https://www.youtube.com/watch?v=kUylIQy-IgI';
    require_once 'inc/class/lib/Embed/src/autoloader.php';
    $embed = Embed\Embed::create($url);
    var_dump($embed);
    echo '<pre>'.print_r($embed,true).'</pre>';

Please help me with this.

Images blacklist

Hi, little feature idea.

What about images blacklist?

Some website always return their logo or whatever useless on open-graph.

Maybe can we have a blacklist solution to ignore some images url?

Thanks.

Error on getting main image

I am getting an error Undefined index: size on line 213 of Utils.php when trying to access the main image.

Here is my current code:

public static function getImage($url) {
    $config = [
        'adapter' => [
            'config' => [
                'minImageWidth' => 16,
                'minImageHeight' => 16,
                'getBiggerImage' => true,
            ]
        ],
        'providers' => [
            'html' => [
                'maxImages' => 3
            ]
        ],
        'resolver' => [
            'config' => [
                CURLOPT_MAXREDIRS => 3
            ]
        ]
    ];

    $info = Embed\Embed::create($url, $config);

    return $info->image;
}

Here's how I'm calling it in my HTML:

<?php print_r(getImage('https://www.youtube.com/watch?v=ULQiCN0YNmw')); ?>

This is the function where the error points to:

public static function getBiggerValue(array $values, $returnKey = false)
{
    $bigger = null;

    foreach ($values as $k => $value) {
        if ($bigger === null || $value['size'] > $values[$bigger]['size']) { // THIS LINE
            $bigger = $k;
        }
    }

    if ($bigger !== null) {
        return $returnKey ? $bigger : $values[$bigger]['value'];
    }
}

What's wrong?

Youtube doesn't work when using Embed on a IPv6 server

I ran into an issue when the embed doesn't work properly for youtube when the request is done through IPv6.
Youtube seems to consider the IPv6 request as spam and respond to request by redirecting all request to a captacha page.

On the same server, by doing the same request on IPv4, it works properly.

So I updated my code to use a CurlIPv4 requestResolver insted of the default one only for youtube request.

Maybe you could do something cleaner to enable an IPv4 for some domains?

Here is what I did:

If I detect youtube.com on the requested URL:

\Embed\Request::setDefaultResolver('NyroDev\\UtilityBundle\\Embed\\RequestResolvers\\CurlIPv4');

Then, you can find the CurlIPv4 class here:
https://github.com/nyroDev/UtilityBundle/blob/master/Embed/RequestResolvers/CurlIPv4.php

The resolve function is actually exactly the same, I just added the line:

CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4

Hope it will help, and thanks for your great work.

Ted provider

Unfortunately, ted does not have discovery on their pages, so a provider is needed.

This is the oembed endpoint for ted:

URL scheme: http://ted.com/talks/* 
Example: http://www.ted.com/talks/oembed.xml?url=http://www.ted.com/talks/jill_bolte_taylor_s_powerful_stroke_of_insight.html

Readme: Resolver configuration.

Hi! I found (correct me if I'm wrong) mistake in readme, in section 'Customization -> The request resolvers'. It says that configuration on resolver should look like this:

$config = [
    'resolver' => [
        'class' => 'Embed\\RequestResolvers\\Curl' //The default resolver used

        'config' => [
            CURLOPT_MAXREDIRS => 20,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_TIMEOUT => 10,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_ENCODING => '',
            CURLOPT_AUTOREFERER => true,
            CURLOPT_USERAGENT => 'Embed PHP Library',
            CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
        ]
    ]
];

But it looks like Embed::create uses $config['request]['resolver'] and $config['request']['config'] code.

Am i right? Imho version from readme is cleaner.

read protected property

object(Embed\Providers\OEmbed)[25]
protected 'parameters' =>
array (size=13)
'provider_url' => string 'http://www.youtube.com/' (length=23)
'thumbnail_height' => string '360' (length=3)
'width' => string '480' (length=3)
'html' => string '<iframe width="480" height="270" src="http://www.youtube.com/embed/PP1xn5wHtxE?feature=oembed" frameborder="0" allowfullscreen></iframe>' (length=136)
'provider_name' => string 'YouTube' (length=7)
'version' => string '1.0' (length=3)
'author_url' => string 'http://www.youtube.com/user/CynicalZipperFallza' (length=47)
'thumbnail_url' => string 'http://i.ytimg.com/vi/PP1xn5wHtxE/hqdefault.jpg' (length=47)
'thumbnail_width' => string '480' (length=3)
'author_name' => string 'CynicalZipperFallza' (length=19)
'height' => string '270' (length=3)
'title' => string '�第7回MMD�Ex】 ロード・オブ・ザ・リング�EVERYBODY' (length=70)

'type' => string 'video' (length=5)

i have the above result,
and i want to read a 'parameters'
,but when i access it the error shown as " Fatal error: Cannot access protected property Embed\Providers\OEmbed::$parameters"
how can i solve this problem.
thanx.

Parse a HTML string

Hello,

Is there any way to parse a HTML string instead of a URL? In my app I already grab the HTML via Guzzle HTTP and I want to parse from the response, not to request the URL all over again.

Image height and width are show as image

Embed test on politico.com

Array
(
    [0] => http://images.politico.com/global/2013/12/18/131218_george_w_bush_barack_obama_ap_605.jpg
    [3] => http://www.politico.com/story/2013/12/605
    [4] => http://www.politico.com/story/2013/12/328
    [6] => http://www.politico.com/design/widgets/x.gif
)

605 and 328 are the width and height of the main image. The URLs of these images aren't valid (404).

This bug seems to be very consistant: Embed test of stackoverflow.com

Html image got, deactivation ignored

Hi and thanks for your project.

Hi have this following configuration:

        $this->embed = Embed::create((string) $articleUrl, [
            'adapter'       => [
                'config'        => [
                    'minImageWidth'  => 300,
                    'minImageHeight' => 200,
                ]
            ],
            'providers'     => [
                'html'          => [
                    'maxImages'     => 0
                ]
            ],
        ]);

In order to deactivate html image provider.

But by calling $this->embed->getImage(); I got some html provider images I don't want.

With this link for example: http://oscarotero.com/embed2/demo/index.php?url=http%3A%2F%2Fsport24.lefigaro.fr%2Frugby%2Fxv-de-france%2Ffil-info%2Fnoves-n-exclut-rien-742945

Is that an issue or a misconfiguration?

Thanks.

Filter out hash bangs in urls

Sometimes, users might try to embed something using a url containing a hash bang: https://twitter.com/#!/twitter/status/99530515043983360.

Curl is not a browser, so it does not evaluate the javascript to load the path after the hash bang.

It would be very nice if the hash bangs in the urls are removed before passing off to curl.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.