| 52 | | abstract public function getCoverArtList($artist, $album, $limit = 0); |
| 53 | | |
| 54 | | public function getCoverArtImage($artist, $album) |
| 55 | | { |
| 56 | | $coverArtList = $this->getCoverArtList($artist, $album, 1); |
| 57 | | $result = array(); |
| 58 | | $this->tryDownloadImage($result, $coverArtList->items, 'image/jpeg'); |
| 59 | | return $result; |
| 60 | | } |
| 61 | | |
| 62 | | public function name() |
| 63 | | { |
| 64 | | return get_class($this); |
| 65 | | } |
| 66 | | |
| 67 | | protected function getHTMLDom($url) |
| 68 | | { |
| 69 | | $startTime = microtime(true); |
| 70 | | |
| 71 | | $dom = new DomDocument(); |
| 72 | | $effectiveURL = $url; |
| 73 | | $html = fetchfile($url, $effectiveURL); |
| 74 | | |
| 75 | | $htmlLoaded = @$dom->loadHTML($html); |
| 76 | | |
| 77 | | $endTime = microtime(true); |
| 78 | | $fetchTime = $endTime - $startTime; |
| 79 | | |
| 80 | | $result->dom = $dom; |
| 81 | | $result->details['fetchTime'] = $fetchTime; |
| 82 | | $result->details['url'] = $url; |
| 83 | | $result->details['effectiveURL'] = $effectiveURL; |
| 84 | | $result->loaded = $htmlLoaded; |
| 85 | | |
| 86 | | return $result; |
| 87 | | } |
| 88 | | |
| 89 | | protected function getDOMNodesByXPath($dom, $xpath, $limit = 0, $xpathStopCondition = "") |
| 90 | | { |
| 91 | | $stopEval = false; |
| 92 | | |
| 93 | | $result->items = array(); |
| 94 | | |
| 95 | | $result->details['xpath'] = $xpath; |
| 96 | | if (!empty($xpathStopCondition)) |
| 97 | | $result->details['xpathStopCondition'] = $xpathStopCondition; |
| 98 | | |
| 99 | | if (isset($dom->dom)) |
| 100 | | $domDoc = $dom->dom; |
| 101 | | else if (is_subclass_of($dom, "DOMNode")) |
| 102 | | { |
| 103 | | $domDoc = $dom->ownerDocument; |
| 104 | | $domNode = $dom; |
| 105 | | } |
| 106 | | else |
| 107 | | $domDoc = NULL; |
| 108 | | |
| 109 | | if (!is_null($domDoc)) |
| 110 | | { |
| 111 | | $xp = new DomXPath($domDoc); |
| 112 | | $stopEval = false; |
| 113 | | |
| 114 | | if (!empty($xpathStopCondition)) |
| 115 | | { |
| 116 | | if (isset($domNode)) |
| 117 | | $items = $xp->evaluate($xpathStopCondition, $domNode); |
| 118 | | else |
| 119 | | $items = $xp->evaluate($xpathStopCondition); |
| 120 | | |
| 121 | | $stopEval = $items->length > 0; |
| 122 | | $result->details['xpathStopConditionMatched'] = $stopEval; |
| 123 | | } |
| 124 | | |
| 125 | | if (!$stopEval) |
| 126 | | { |
| 127 | | $startTime = microtime(true); |
| 128 | | |
| 129 | | if (isset($domNode)) |
| 130 | | $items = $xp->evaluate($xpath, $domNode); |
| 131 | | else |
| 132 | | $items = $xp->evaluate($xpath); |
| 133 | | |
| 134 | | if (is_object($items)) |
| 135 | | { |
| 136 | | $i = 0; |
| 137 | | foreach ($items as $item) |
| 138 | | { |
| 139 | | $result->items[] = $item; |
| 140 | | ++$i; |
| 141 | | |
| 142 | | if ($limit > 0 && $i == $limit) |
| 143 | | break; |
| 144 | | } |
| 145 | | } |
| 146 | | else if (!empty($items)) |
| 147 | | $result->items[] = $items; |
| 148 | | |
| 149 | | $count = count($result->items); |
| 150 | | |
| 151 | | $endTime = microtime(true); |
| 152 | | $evalTime = $endTime - $startTime; |
| 153 | | $result->details['evalTime'] = $evalTime; |
| 154 | | } |
| 155 | | } |
| 156 | | |
| 157 | | return $result; |
| 158 | | } |
| 159 | | |
| 160 | | protected function getListByXPath($dom, $xpath, $limit = 0, $xpathStopCondition = "", $invalidItemFilter = "") |
| 161 | | { |
| 162 | | $result = $this->getDOMNodesByXPath($dom, $xpath, $limit, $xpathStopCondition); |
| 163 | | |
| 164 | | foreach ($result->items as $item) |
| 165 | | { |
| 166 | | if (is_object($item)) |
| 167 | | $item = $item->nodeValue; |
| 168 | | |
| 169 | | if (!empty($item) && $item != $invalidItemFilter) |
| 170 | | $list[] = $item; |
| 171 | | } |
| 172 | | |
| 173 | | $result->items = $list; |
| 174 | | |
| 175 | | return $result; |
| 176 | | } |
| 177 | | |
| 178 | | protected function tryDownloadImage(&$result, $imageURLs, $mimetype = 'image/jpeg') |
| 179 | | { |
| 180 | | $result['success'] = false; |
| 181 | | |
| 182 | | if (count($imageURLs) > 0) |
| 183 | | { |
| 184 | | $imageData = false; |
| 185 | | $i = 0; |
| 186 | | while ($imageData === false && $i < count($imageURLs)) |
| 187 | | { |
| 188 | | $imageData = fetchfile($imageURLs[$i]); |
| 189 | | ++$i; |
| 190 | | } |
| 191 | | |
| 192 | | if ($imageData) |
| 193 | | { |
| 194 | | $result['imagedata'] = $imageData; |
| 195 | | $result['mimetype'] = $mimetype; |
| 196 | | $result['success'] = true; |
| 197 | | } |
| 198 | | } |
| 199 | | } |
| | 52 | abstract public function getCoverArtList($artist, $album, $limit = 0); |
| | 53 | |
| | 54 | public function getCoverArtImage($artist, $album) |
| | 55 | { |
| | 56 | $coverArtList = $this->getCoverArtList($artist, $album, 1); |
| | 57 | $result = array(); |
| | 58 | $this->tryDownloadImage($result, $coverArtList->items, 'image/jpeg'); |
| | 59 | return $result; |
| | 60 | } |
| | 61 | |
| | 62 | public function name() |
| | 63 | { |
| | 64 | return get_class($this); |
| | 65 | } |
| | 66 | |
| | 67 | protected function getHTMLDom($url) |
| | 68 | { |
| | 69 | $startTime = microtime(true); |
| | 70 | |
| | 71 | $dom = new DomDocument(); |
| | 72 | $effectiveURL = $url; |
| | 73 | $html = fetchfile($url, $effectiveURL); |
| | 74 | |
| | 75 | $htmlLoaded = @$dom->loadHTML($html); |
| | 76 | |
| | 77 | $endTime = microtime(true); |
| | 78 | $fetchTime = $endTime - $startTime; |
| | 79 | |
| | 80 | $result->dom = $dom; |
| | 81 | $result->details['fetchTime'] = $fetchTime; |
| | 82 | $result->details['url'] = $url; |
| | 83 | $result->details['effectiveURL'] = $effectiveURL; |
| | 84 | $result->loaded = $htmlLoaded; |
| | 85 | |
| | 86 | return $result; |
| | 87 | } |
| | 88 | |
| | 89 | protected function getDOMNodesByXPath($dom, $xpath, $limit = 0, $xpathStopCondition = "") |
| | 90 | { |
| | 91 | $stopEval = false; |
| | 92 | |
| | 93 | $result->items = array(); |
| | 94 | |
| | 95 | $result->details['xpath'] = $xpath; |
| | 96 | if (!empty($xpathStopCondition)) |
| | 97 | $result->details['xpathStopCondition'] = $xpathStopCondition; |
| | 98 | |
| | 99 | if (isset($dom->dom)) |
| | 100 | $domDoc = $dom->dom; |
| | 101 | else if (is_subclass_of($dom, "DOMNode")) |
| | 102 | { |
| | 103 | $domDoc = $dom->ownerDocument; |
| | 104 | $domNode = $dom; |
| | 105 | } |
| | 106 | else |
| | 107 | $domDoc = NULL; |
| | 108 | |
| | 109 | if (!is_null($domDoc)) |
| | 110 | { |
| | 111 | $xp = new DomXPath($domDoc); |
| | 112 | $stopEval = false; |
| | 113 | |
| | 114 | if (!empty($xpathStopCondition)) |
| | 115 | { |
| | 116 | if (isset($domNode)) |
| | 117 | $items = $xp->evaluate($xpathStopCondition, $domNode); |
| | 118 | else |
| | 119 | $items = $xp->evaluate($xpathStopCondition); |
| | 120 | |
| | 121 | $stopEval = $items->length > 0; |
| | 122 | $result->details['xpathStopConditionMatched'] = $stopEval; |
| | 123 | } |
| | 124 | |
| | 125 | if (!$stopEval) |
| | 126 | { |
| | 127 | $startTime = microtime(true); |
| | 128 | |
| | 129 | if (isset($domNode)) |
| | 130 | $items = $xp->evaluate($xpath, $domNode); |
| | 131 | else |
| | 132 | $items = $xp->evaluate($xpath); |
| | 133 | |
| | 134 | if (is_object($items)) |
| | 135 | { |
| | 136 | $i = 0; |
| | 137 | foreach ($items as $item) |
| | 138 | { |
| | 139 | $result->items[] = $item; |
| | 140 | ++$i; |
| | 141 | |
| | 142 | if ($limit > 0 && $i == $limit) |
| | 143 | break; |
| | 144 | } |
| | 145 | } |
| | 146 | else if (!empty($items)) |
| | 147 | $result->items[] = $items; |
| | 148 | |
| | 149 | $count = count($result->items); |
| | 150 | |
| | 151 | $endTime = microtime(true); |
| | 152 | $evalTime = $endTime - $startTime; |
| | 153 | $result->details['evalTime'] = $evalTime; |
| | 154 | } |
| | 155 | } |
| | 156 | |
| | 157 | return $result; |
| | 158 | } |
| | 159 | |
| | 160 | protected function getListByXPath($dom, $xpath, $limit = 0, $xpathStopCondition = "", $invalidItemFilter = "") |
| | 161 | { |
| | 162 | $result = $this->getDOMNodesByXPath($dom, $xpath, $limit, $xpathStopCondition); |
| | 163 | |
| | 164 | foreach ($result->items as $item) |
| | 165 | { |
| | 166 | if (is_object($item)) |
| | 167 | $item = $item->nodeValue; |
| | 168 | |
| | 169 | if (!empty($item) && $item != $invalidItemFilter) |
| | 170 | $list[] = $item; |
| | 171 | } |
| | 172 | |
| | 173 | $result->items = $list; |
| | 174 | |
| | 175 | return $result; |
| | 176 | } |
| | 177 | |
| | 178 | protected function tryDownloadImage(&$result, $imageURLs, $mimetype = 'image/jpeg') |
| | 179 | { |
| | 180 | $result['success'] = false; |
| | 181 | |
| | 182 | if (count($imageURLs) > 0) |
| | 183 | { |
| | 184 | $imageData = false; |
| | 185 | $i = 0; |
| | 186 | while ($imageData === false && $i < count($imageURLs)) |
| | 187 | { |
| | 188 | $imageData = fetchfile($imageURLs[$i]); |
| | 189 | ++$i; |
| | 190 | } |
| | 191 | |
| | 192 | if ($imageData) |
| | 193 | { |
| | 194 | $result['imagedata'] = $imageData; |
| | 195 | $result['mimetype'] = $mimetype; |
| | 196 | $result['success'] = true; |
| | 197 | } |
| | 198 | } |
| | 199 | } |
| 204 | | public function getCoverArtList($artist, $album, $limit = 0) |
| 205 | | { |
| 206 | | // Walmart returns an image even if it doesn't have a cover available |
| 207 | | // Currently there is no way to detect the placeholder image without inspecting the |
| 208 | | // image data... |
| 209 | | $list->results = array(); |
| 210 | | |
| 211 | | $dom = $this->getHTMLDom('http://www.walmart.com/catalog/search-ng.gsp?search_constraint=4104&search_query=' . urlencode($artist . ', ' . $album)); |
| 212 | | $list->details[] = $dom; |
| 213 | | |
| 214 | | $photoNodes = $this->getDOMNodesByXPath($dom, '//div[@class="BoxContent"]//div[starts-with(@class, "LargeItemPhoto")]'); |
| 215 | | $list->details[] = $photoNodes; |
| 216 | | |
| 217 | | if (count($photoNodes->items) > 0) |
| 218 | | { |
| 219 | | $titleList = $this->getListByXPath($photoNodes->items[0], './a/img/@alt'); $list->details[] = $titleList; |
| 220 | | $thumbnailImageList = $this->getListByXPath($photoNodes->items[0], './a/img/@src'); $list->details[] = $thumbnailImageList; |
| 221 | | $imageList = $this->getListByXPath($photoNodes->items[0], 'substring-before(substring-after(./a/@href, "photo_opener(\'"), "&product_id=")'); $list->details[] = $imageList; |
| 222 | | |
| 223 | | $coverArtItem = new CoverArtResult(); |
| 224 | | $coverArtItem->title = $titleList->items[0]; |
| 225 | | $coverArtItem->detailsURL = $dom->details["effectiveURL"]; |
| 226 | | $coverArtItem->thumbnailImageURL = $thumbnailImageList->items[0]; |
| 227 | | $coverArtItem->imageURL = $imageList->items[0]; |
| 228 | | $list->results[] = $coverArtItem; |
| 229 | | } |
| 230 | | |
| 231 | | return $list; |
| 232 | | } |
| | 204 | public function getCoverArtList($artist, $album, $limit = 0) |
| | 205 | { |
| | 206 | // Walmart returns an image even if it doesn't have a cover available |
| | 207 | // Currently there is no way to detect the placeholder image without inspecting the |
| | 208 | // image data... |
| | 209 | $list->results = array(); |
| | 210 | |
| | 211 | $dom = $this->getHTMLDom('http://www.walmart.com/catalog/search-ng.do?search_constraint=4104&search_query=' . urlencode($artist . ', ' . $album)); |
| | 212 | $list->details[] = $dom; |
| | 213 | |
| | 214 | $photoNodes = $this->getDOMNodesByXPath($dom, '//div[@class="BoxContent"]//div[starts-with(@class, "LargeItemPhoto")]'); |
| | 215 | $list->details[] = $photoNodes; |
| | 216 | |
| | 217 | if (count($photoNodes->items) > 0) |
| | 218 | { |
| | 219 | $titleList = $this->getListByXPath($photoNodes->items[0], './a/img/@alt'); $list->details[] = $titleList; |
| | 220 | $thumbnailImageList = $this->getListByXPath($photoNodes->items[0], './a/img/@src'); $list->details[] = $thumbnailImageList; |
| | 221 | $imageList = $this->getListByXPath($photoNodes->items[0], 'substring-before(substring-after(./a/@href, "photo_opener(\'"), "&product_id=")'); $list->details[] = $imageList; |
| | 222 | |
| | 223 | $coverArtItem = new CoverArtResult(); |
| | 224 | $coverArtItem->title = $titleList->items[0]; |
| | 225 | $coverArtItem->detailsURL = $dom->details["effectiveURL"]; |
| | 226 | $coverArtItem->thumbnailImageURL = $thumbnailImageList->items[0]; |
| | 227 | $coverArtItem->imageURL = $imageList->items[0]; |
| | 228 | $list->results[] = $coverArtItem; |
| | 229 | } |
| | 230 | |
| | 231 | return $list; |
| | 232 | } |
| 237 | | public function getCoverArtList($artist, $album, $limit = 0) |
| 238 | | { |
| 239 | | $list->results = array(); |
| 240 | | |
| 241 | | $dom = $this->getHTMLDom('http://www.buy.com/retail/searchresults.asp?search_store=6&qu=' . urlencode($artist . ' ' . $album)); |
| 242 | | $list->details[] = $dom; |
| 243 | | |
| 244 | | $resultNodes = $this->getDOMNodesByXPath( |
| 245 | | $dom, |
| 246 | | '//form[@name="frmSearchProducts"]//td[(@class="listTop" or @class="list") and count(./a/@href) = 1]', |
| 247 | | 0, |
| 248 | | '//*[contains(text(), "We could not find an exact match")]' // Buy.com automatically estimates if no exact match is found, so stop as soon as we detect this... |
| 249 | | ); |
| 250 | | $list->details[] = $resultNodes; |
| 251 | | |
| 252 | | $count = 0; |
| 253 | | foreach ($resultNodes->items as $resultNode) |
| 254 | | { |
| 255 | | $titleList = $this->getListByXPath($resultNode, './a/img/@alt'); $list->details[] = $titleList; |
| 256 | | $detailsList = $this->getListByXPath($resultNode, 'concat("http://www.buy.com", ./a/@href)'); $list->details[] = $detailsList; |
| 257 | | $thumbnailImageList = $this->getListByXPath($resultNode, './a/img/@src'); $list->details[] = $thumbnailImageList; |
| 258 | | |
| 259 | | if (isset($detailsList->items[0])) |
| 260 | | { |
| 261 | | $dom = $this->getHTMLDom($detailsList->items[0]); |
| 262 | | $imageList = $this->getListByXPath($dom, 'substring-before(substring-after(//div[@id="mainImgSection"]//a[@id="PROD_lrg_img_link"]/@href, "largeIMTop(\'"), "\',\'")'); |
| 263 | | $list->details[] = $imageList; |
| 264 | | |
| 265 | | if (count($imageList->items) > 0) |
| 266 | | { |
| 267 | | $coverArtItem = new CoverArtResult(); |
| 268 | | $coverArtItem->title = $titleList->items[0]; |
| 269 | | $coverArtItem->detailsURL = $detailsList->items[0]; |
| 270 | | $coverArtItem->thumbnailImageURL = $thumbnailImageList->items[0]; |
| 271 | | $coverArtItem->imageURL = $imageList->items[0]; |
| 272 | | $list->results[] = $coverArtItem; |
| 273 | | |
| 274 | | ++$count; |
| 275 | | if ($count == $limit) |
| 276 | | break; |
| 277 | | } |
| 278 | | } |
| 279 | | } |
| 280 | | |
| 281 | | return $list; |
| 282 | | } |
| | 237 | public function getCoverArtList($artist, $album, $limit = 0) |
| | 238 | { |
| | 239 | $list->results = array(); |
| | 240 | |
| | 241 | $dom = $this->getHTMLDom('http://www.buy.com/retail/searchresults.asp?search_store=6&qu=' . urlencode($artist . ' ' . $album)); |
| | 242 | $list->details[] = $dom; |
| | 243 | |
| | 244 | $resultNodes = $this->getDOMNodesByXPath( |
| | 245 | $dom, |
| | 246 | '//form[@name="frmSearchProducts"]//td[(@class="listTop" or @class="list") and count(./a/@href) = 1]', |
| | 247 | 0, |
| | 248 | '//*[contains(text(), "We could not find an exact match")]' // Buy.com automatically estimates if no exact match is found, so stop as soon as we detect this... |
| | 249 | ); |
| | 250 | $list->details[] = $resultNodes; |
| | 251 | |
| | 252 | $count = 0; |
| | 253 | foreach ($resultNodes->items as $resultNode) |
| | 254 | { |
| | 255 | $titleList = $this->getListByXPath($resultNode, './a/img/@alt'); $list->details[] = $titleList; |
| | 256 | $detailsList = $this->getListByXPath($resultNode, 'concat("http://www.buy.com", ./a/@href)'); $list->details[] = $detailsList; |
| | 257 | $thumbnailImageList = $this->getListByXPath($resultNode, './a/img/@src'); $list->details[] = $thumbnailImageList; |
| | 258 | |
| | 259 | if (isset($detailsList->items[0])) |
| | 260 | { |
| | 261 | $dom = $this->getHTMLDom($detailsList->items[0]); |
| | 262 | $imageList = $this->getListByXPath($dom, 'substring-before(substring-after(//div[@id="mainImgSection"]//a[@id="PROD_lrg_img_link"]/@href, "largeIMTop(\'"), "\',\'")'); |
| | 263 | $list->details[] = $imageList; |
| | 264 | |
| | 265 | if (count($imageList->items) > 0) |
| | 266 | { |
| | 267 | $coverArtItem = new CoverArtResult(); |
| | 268 | $coverArtItem->title = $titleList->items[0]; |
| | 269 | $coverArtItem->detailsURL = $detailsList->items[0]; |
| | 270 | $coverArtItem->thumbnailImageURL = $thumbnailImageList->items[0]; |
| | 271 | $coverArtItem->imageURL = $imageList->items[0]; |
| | 272 | $list->results[] = $coverArtItem; |
| | 273 | |
| | 274 | ++$count; |
| | 275 | if ($count == $limit) |
| | 276 | break; |
| | 277 | } |
| | 278 | } |
| | 279 | } |
| | 280 | |
| | 281 | return $list; |
| | 282 | } |
| 287 | | private $topLevelDomain; |
| 288 | | |
| 289 | | function __construct($topLevelDomain = "com") |
| 290 | | { |
| 291 | | $this->topLevelDomain = $topLevelDomain; |
| 292 | | } |
| 293 | | |
| 294 | | public function name() |
| 295 | | { |
| 296 | | return AbstractCoverArtProvider::name() . "_" . $this->topLevelDomain; |
| 297 | | } |
| 298 | | |
| 299 | | public function getCoverArtList($artist, $album, $limit = 0) |
| 300 | | { |
| 301 | | $list->results = array(); |
| 302 | | |
| 303 | | $dom = $this->getHTMLDom('http://www.amazon.' . $this->topLevelDomain . '/gp/search/?search-alias=popular&unfiltered=1&sort=salesrank&field-keywords=&field-artist=' . urlencode(utf8_decode($artist)) . '&field-title=' . urlencode(utf8_decode($album))); |
| 304 | | $list->details[] = $dom; |
| 305 | | |
| 306 | | $resultNodes = $this->getDOMNodesByXPath( |
| 307 | | $dom, |
| 308 | | '//div[@id="Results"]//td[starts-with(@id, "search:Td")]//table[@class="n2"]//tr[.//td/@class="imageColumn" and not(contains(.//img/@src, "no-img-"))]', |
| 309 | | // '//div[@id="Results"]//div[@class="productImage"]//a[not(contains(img/@src, "no-img-"))]/img/@src', |
| 310 | | $limit |
| 311 | | ); |
| 312 | | $list->details[] = $resultNodes; |
| 313 | | |
| 314 | | foreach ($resultNodes->items as $resultNode) |
| 315 | | { |
| 316 | | $titleList = $this->getListByXPath($resultNode, './/td[@class="dataColumn"]//span[@class="srTitle"]/text()'); $list->details[] = $titleList; |
| 317 | | $detailsList = $this->getListByXPath($resultNode, './/td[@class="dataColumn"]//a[./span/@class="srTitle"]/@href'); $list->details[] = $detailsList; |
| 318 | | $thumbnailImageList = $this->getListByXPath($resultNode, './/td[@class="imageColumn"]//a/img/@src'); $list->details[] = $thumbnailImageList; |
| 319 | | |
| 320 | | $coverArtItem = new CoverArtResult(); |
| 321 | | $coverArtItem->title = $titleList->items[0]; |
| 322 | | $coverArtItem->detailsURL = $detailsList->items[0]; |
| 323 | | $coverArtItem->thumbnailImageURL = $thumbnailImageList->items[0]; |
| 324 | | $coverArtItem->imageURL = substr($coverArtItem->thumbnailImageURL, 0, strpos($coverArtItem->thumbnailImageURL, "._")) . '._SL500_.jpg'; |
| 325 | | $list->results[] = $coverArtItem; |
| 326 | | } |
| 327 | | |
| 328 | | return $list; |
| 329 | | } |
| | 287 | private $topLevelDomain; |
| | 288 | |
| | 289 | function __construct($topLevelDomain = "com") |
| | 290 | { |
| | 291 | $this->topLevelDomain = $topLevelDomain; |
| | 292 | } |
| | 293 | |
| | 294 | public function name() |
| | 295 | { |
| | 296 | return AbstractCoverArtProvider::name() . "_" . $this->topLevelDomain; |
| | 297 | } |
| | 298 | |
| | 299 | public function getCoverArtList($artist, $album, $limit = 0) |
| | 300 | { |
| | 301 | $list->results = array(); |
| | 302 | |
| | 303 | $dom = $this->getHTMLDom('http://www.amazon.' . $this->topLevelDomain . '/gp/search/?search-alias=popular&unfiltered=1&sort=salesrank&field-keywords=&field-artist=' . urlencode(utf8_decode($artist)) . '&field-title=' . urlencode(utf8_decode($album))); |
| | 304 | $list->details[] = $dom; |
| | 305 | |
| | 306 | $resultNodes = $this->getDOMNodesByXPath( |
| | 307 | $dom, |
| | 308 | '//div[@id="atfResults" or @id="btfResults"]//div[starts-with(@id, "result_") and .//div/@class="image" and not(contains(.//img/@src, "no-img-"))]', |
| | 309 | $limit |
| | 310 | ); |
| | 311 | $list->details[] = $resultNodes; |
| | 312 | |
| | 313 | foreach ($resultNodes->items as $resultNode) |
| | 314 | { |
| | 315 | $titleList = $this->getListByXPath($resultNode, './/div[@class="data"]//a[@class="title"]/text()'); $list->details[] = $titleList; |
| | 316 | $detailsList = $this->getListByXPath($resultNode, './/div[@class="data"]//a[@class="title"]/@href'); $list->details[] = $detailsList; |
| | 317 | $thumbnailImageList = $this->getListByXPath($resultNode, './/div[@class="image"]//a/img/@src'); $list->details[] = $thumbnailImageList; |
| | 318 | |
| | 319 | $coverArtItem = new CoverArtResult(); |
| | 320 | $coverArtItem->title = $titleList->items[0]; |
| | 321 | $coverArtItem->detailsURL = $detailsList->items[0]; |
| | 322 | $coverArtItem->thumbnailImageURL = $thumbnailImageList->items[0]; |
| | 323 | $coverArtItem->imageURL = substr($coverArtItem->thumbnailImageURL, 0, strpos($coverArtItem->thumbnailImageURL, "._")) . '._SL500_.jpg'; |
| | 324 | $list->results[] = $coverArtItem; |
| | 325 | } |
| | 326 | |
| | 327 | return $list; |
| | 328 | } |
| 334 | | private $topLevelDomain; |
| 335 | | |
| 336 | | function __construct($topLevelDomain = "com") |
| 337 | | { |
| 338 | | $this->topLevelDomain = $topLevelDomain; |
| 339 | | } |
| 340 | | |
| 341 | | public function name() |
| 342 | | { |
| 343 | | return AbstractCoverArtProvider::name() . "_" . $this->topLevelDomain; |
| 344 | | } |
| 345 | | |
| 346 | | public function getCoverArtList($artist, $album, $limit = 0) |
| 347 | | { |
| 348 | | $list->results = array(); |
| 349 | | |
| 350 | | $dom = $this->getHTMLDom('http://images.google.' . $this->topLevelDomain . '/images?q=Album+%22' . urlencode(utf8_decode($artist)) . '%22+%22' . urlencode(utf8_decode($album)) . '%22&hl=en&sa=G&gbv=1'); |
| 351 | | $list->details[] = $dom; |
| 352 | | |
| 353 | | $resultNodes = $this->getDOMNodesByXPath($dom, '//div[@id="ImgCont"]//a[starts-with(@href, "/imgres?imgurl=")]', $limit); |
| 354 | | $list->details[] = $resultNodes; |
| 355 | | |
| 356 | | foreach ($resultNodes->items as $resultNode) |
| 357 | | { |
| 358 | | $imageList = $this->getListByXPath($resultNode, 'substring-before(substring-after(./@href, "/imgres?imgurl="), "&imgrefurl=")'); $list->details[] = $imageList; |
| 359 | | $detailsList = $this->getListByXPath($resultNode, 'substring-before(substring-after(./@href, "&imgrefurl="), "&usg=")'); $list->details[] = $detailsList; |
| 360 | | $thumbnailImageList = $this->getListByXPath($resultNode, '..//img/@src'); $list->details[] = $thumbnailImageList; |
| 361 | | |
| 362 | | $coverArtItem = new CoverArtResult(); |
| 363 | | $coverArtItem->title = ""; |
| 364 | | $coverArtItem->detailsURL = $detailsList->items[0]; |
| 365 | | $coverArtItem->thumbnailImageURL = $thumbnailImageList->items[0]; |
| 366 | | $coverArtItem->imageURL = $imageList->items[0]; |
| 367 | | $list->results[] = $coverArtItem; |
| 368 | | } |
| 369 | | |
| 370 | | return $list; |
| 371 | | } |
| | 333 | private $topLevelDomain; |
| | 334 | |
| | 335 | function __construct($topLevelDomain = "com") |
| | 336 | { |
| | 337 | $this->topLevelDomain = $topLevelDomain; |
| | 338 | } |
| | 339 | |
| | 340 | public function name() |
| | 341 | { |
| | 342 | return AbstractCoverArtProvider::name() . "_" . $this->topLevelDomain; |
| | 343 | } |
| | 344 | |
| | 345 | public function getCoverArtList($artist, $album, $limit = 0) |
| | 346 | { |
| | 347 | $list->results = array(); |
| | 348 | |
| | 349 | $dom = $this->getHTMLDom('http://images.google.' . $this->topLevelDomain . '/images?q=Album+%22' . urlencode(utf8_decode($artist)) . '%22+%22' . urlencode(utf8_decode($album)) . '%22&hl=en&sa=G&gbv=1'); |
| | 350 | $list->details[] = $dom; |
| | 351 | |
| | 352 | $resultNodes = $this->getDOMNodesByXPath($dom, '//div[@id="ires"]//a[starts-with(@href, "/imgres?imgurl=")]', $limit); |
| | 353 | $list->details[] = $resultNodes; |
| | 354 | |
| | 355 | foreach ($resultNodes->items as $resultNode) |
| | 356 | { |
| | 357 | $imageList = $this->getListByXPath($resultNode, 'substring-before(substring-after(./@href, "/imgres?imgurl="), "&imgrefurl=")'); $list->details[] = $imageList; |
| | 358 | $detailsList = $this->getListByXPath($resultNode, 'substring-before(substring-after(./@href, "&imgrefurl="), "&usg=")'); $list->details[] = $detailsList; |
| | 359 | $thumbnailImageList = $this->getListByXPath($resultNode, '..//img/@src'); $list->details[] = $thumbnailImageList; |
| | 360 | |
| | 361 | $coverArtItem = new CoverArtResult(); |
| | 362 | $coverArtItem->title = ""; |
| | 363 | $coverArtItem->detailsURL = $detailsList->items[0]; |
| | 364 | $coverArtItem->thumbnailImageURL = $thumbnailImageList->items[0]; |
| | 365 | $coverArtItem->imageURL = $imageList->items[0]; |
| | 366 | $list->results[] = $coverArtItem; |
| | 367 | } |
| | 368 | |
| | 369 | return $list; |
| | 370 | } |
| 377 | | private $coverArtProviders; |
| 378 | | private $coverArtProviderQueryLimit; |
| 379 | | private $dbh; |
| 380 | | private $selectStmt; |
| 381 | | private $insertSearchStmt; |
| 382 | | private $insertResultStmt; |
| 383 | | |
| 384 | | function __construct($coverArtProviders = NULL, $coverArtProviderQueryLimit = 0) |
| 385 | | { |
| 386 | | if (is_null($coverArtProviders)) |
| 387 | | { |
| 388 | | global $globalCoverArtProviders; |
| 389 | | $coverArtProviders = $globalCoverArtProviders; |
| 390 | | } |
| 391 | | |
| 392 | | $this->coverArtProviders = $coverArtProviders; |
| 393 | | $this->coverArtProviderQueryLimit = $coverArtProviderQueryLimit; |
| 394 | | |
| 395 | | $createDB = !file_exists(CACHE_SQLITE_FILE); |
| 396 | | |
| 397 | | $this->dbh = new PDO('sqlite:' . CACHE_SQLITE_FILE); |
| 398 | | |
| 399 | | if ($createDB) |
| 400 | | { |
| 401 | | $this->dbh->exec(' |
| 402 | | CREATE TABLE "searches" ( |
| 403 | | "search_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, |
| 404 | | "provider_name" TEXT NOT NULL COLLATE NOCASE, |
| 405 | | "artist" TEXT NOT NULL COLLATE NOCASE, |
| 406 | | "album" TEXT NOT NULL COLLATE NOCASE, |
| 407 | | "timestamp" INTEGER NOT NULL |
| 408 | | ); |
| 409 | | |
| 410 | | CREATE TABLE "searches_results" ( |
| 411 | | "result_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, |
| 412 | | "search_id" INTEGER, |
| 413 | | "index" INTEGER NOT NULL, |
| 414 | | "title" TEXT NOT NULL, |
| 415 | | "details_url" TEXT NOT NULL, |
| 416 | | "thumbnail_image_url" TEXT NOT NULL, |
| 417 | | "image_url" TEXT NOT NULL |
| 418 | | ); |
| 419 | | |
| 420 | | CREATE INDEX "searches_provider_name" on searches (provider_name ASC); |
| 421 | | CREATE INDEX "searches_artist" on searches (artist ASC); |
| 422 | | CREATE INDEX "searches_album" on searches (album ASC); |
| 423 | | CREATE INDEX "searches_results_search_id" on searches_results (search_id ASC); |
| 424 | | |
| 425 | | CREATE TRIGGER delete_searches_results DELETE ON searches |
| 426 | | BEGIN |
| 427 | | DELETE FROM searches_results WHERE search_id = OLD.search_id; |
| 428 | | END; |
| 429 | | '); |
| 430 | | } |
| 431 | | |
| 432 | | $this->selectStmt = $this->dbh->prepare( |
| 433 | | "SELECT * FROM searches " . |
| 434 | | "LEFT JOIN searches_results AS sr ON sr.search_id = searches.search_id " . |
| 435 | | "WHERE provider_name = ? AND artist = ? AND album = ? ORDER BY `index`;" |
| 436 | | ); |
| 437 | | |
| 438 | | if (!$this->selectStmt) |
| 439 | | { |
| 440 | | echo "\nPDO::errorInfo():\n"; |
| 441 | | print_r($this->dbh->errorInfo()); |
| 442 | | } |
| 443 | | |
| 444 | | $this->insertSearchStmt = $this->dbh->prepare( |
| 445 | | "INSERT INTO searches (search_id, provider_name, artist, album, timestamp) " . |
| 446 | | "VALUES (NULL, ?, ?, ?, ?);" |
| 447 | | ); |
| 448 | | |
| 449 | | if (!$this->insertSearchStmt) |
| 450 | | { |
| 451 | | echo "\nPDO::errorInfo():\n"; |
| 452 | | print_r($this->dbh->errorInfo()); |
| 453 | | } |
| 454 | | |
| 455 | | $this->insertResultStmt = $this->dbh->prepare( |
| 456 | | "INSERT INTO searches_results (result_id, search_id, `index`, title, details_url, thumbnail_image_url, image_url) " . |
| 457 | | "VALUES (NULL, ?, ?, ?, ?, ?, ?);" |
| 458 | | ); |
| 459 | | |
| 460 | | if (!$this->insertResultStmt) |
| 461 | | { |
| 462 | | echo "\nPDO::errorInfo():\n"; |
| 463 | | print_r($this->dbh->errorInfo()); |
| 464 | | } |
| 465 | | } |
| 466 | | |
| 467 | | public function getCoverArtList($artist, $album, $limit = 0) |
| 468 | | { |
| 469 | | $listLimit = $limit; |
| 470 | | $list->results = array(); |
| 471 | | |
| 472 | | $coverArtProviderQueried = 0; |
| 473 | | |
| 474 | | foreach ($this->coverArtProviders as $provider) |
| 475 | | { |
| 476 | | $success = $this->selectStmt->execute(array($provider->name(), $artist, $album)); |
| 477 | | $rows = $this->selectStmt->fetchAll(); |
| 478 | | $resultsValid = false; |
| 479 | | |
| 480 | | if ($success && count($rows) > 0) |
| 481 | | { |
| 482 | | $resultsValid = $rows[0]["timestamp"] > time() - CACHE_EXPIRY_SECONDS; |
| 483 | | if (!$resultsValid) |
| 484 | | { |
| 485 | | echo "Cached results expired, removing " . $rows[0][0]; |
| 486 | | $this->dbh->exec("DELETE FROM searches WHERE search_id = " . $rows[0][0] . ";"); |
| 487 | | } |
| 488 | | } |
| 489 | | |
| 490 | | if ($resultsValid) |
| 491 | | { |
| 492 | | //echo "Something was found in the cache..."; |
| 493 | | $coverArtList->results = array(); |
| 494 | | |
| 495 | | foreach ($rows as $row) |
| 496 | | { |
| 497 | | if (is_null($row["image_url"])) |
| 498 | | break; |
| 499 | | |
| 500 | | $coverArtItem = new CoverArtResult(); |
| 501 | | $coverArtItem->title = $row["title"]; |
| 502 | | $coverArtItem->detailsURL = $row["details_url"]; |
| 503 | | $coverArtItem->thumbnailImageURL = $row["thumbnail_image_url"]; |
| 504 | | $coverArtItem->imageURL = $row["image_url"]; |
| 505 | | $coverArtList->results[] = $coverArtItem; |
| 506 | | |
| 507 | | if ($limit > 0 && count($coverArtList->results) == $listLimit) |
| 508 | | break; |
| 509 | | } |
| 510 | | } |
| 511 | | else |
| 512 | | { |
| 513 | | //echo "Nothing found in the cache..."; |
| 514 | | $coverArtList = $provider->getCoverArtList($artist, $album, $listLimit); |
| 515 | | |
| 516 | | $this->dbh->beginTransaction(); |
| 517 | | |
| 518 | | if ($this->insertSearchStmt->execute(array($provider->name(), $artist, $album, time()))) |
| 519 | | { |
| 520 | | $searchID = $this->dbh->lastInsertId(); |
| 521 | | //echo "Search inserted: " . $searchID; |
| 522 | | |
| 523 | | foreach ($coverArtList->results as $index => $result) |
| 524 | | { |
| 525 | | $this->insertResultStmt->execute(array( |
| 526 | | $searchID, |
| 527 | | $index, |
| 528 | | $result->title, |
| 529 | | $result->detailsURL, |
| 530 | | $result->thumbnailImageURL, |
| 531 | | $result->imageURL |
| 532 | | )); |
| 533 | | } |
| 534 | | } |
| 535 | | |
| 536 | | $this->dbh->commit(); |
| 537 | | } |
| 538 | | |
| 539 | | $list->results = array_merge($list->results, $coverArtList->results); |
| 540 | | |
| 541 | | if ($limit > 0) |
| 542 | | { |
| 543 | | $listLimit = max(0, $listLimit - count($coverArtList->results)); |
| 544 | | if ($listLimit == 0) |
| 545 | | break; |
| 546 | | } |
| 547 | | |
| 548 | | if (count($coverArtList->results) > 0) |
| 549 | | ++$coverArtProviderQueried; |
| 550 | | |
| 551 | | if ($this->coverArtProviderQueryLimit > 0 && |
| 552 | | count($coverArtList->results) > 0 && |
| 553 | | $coverArtProviderQueried == $this->coverArtProviderQueryLimit) |
| 554 | | break; |
| 555 | | } |
| 556 | | |
| 557 | | return $list; |
| 558 | | } |
| | 376 | private $coverArtProviders; |
| | 377 | private $coverArtProviderQueryLimit; |
| | 378 | private $dbh; |
| | 379 | private $selectStmt; |
| | 380 | private $insertSearchStmt; |
| | 381 | private $insertResultStmt; |
| | 382 | |
| | 383 | function __construct($coverArtProviders = NULL, $coverArtProviderQueryLimit = 0) |
| | 384 | { |
| | 385 | if (is_null($coverArtProviders)) |
| | 386 | { |
| | 387 | global $globalCoverArtProviders; |
| | 388 | $coverArtProviders = $globalCoverArtProviders; |
| | 389 | } |
| | 390 | |
| | 391 | $this->coverArtProviders = $coverArtProviders; |
| | 392 | $this->coverArtProviderQueryLimit = $coverArtProviderQueryLimit; |
| | 393 | |
| | 394 | $createDB = !file_exists(CACHE_SQLITE_FILE); |
| | 395 | |
| | 396 | $this->dbh = new PDO('sqlite:' . CACHE_SQLITE_FILE); |
| | 397 | |
| | 398 | if ($createDB) |
| | 399 | { |
| | 400 | $this->dbh->exec(' |
| | 401 | CREATE TABLE "searches" ( |
| | 402 | "search_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, |
| | 403 | "provider_name" TEXT NOT NULL COLLATE NOCASE, |
| | 404 | "artist" TEXT NOT NULL COLLATE NOCASE, |
| | 405 | "album" TEXT NOT NULL COLLATE NOCASE, |
| | 406 | "timestamp" INTEGER NOT NULL |
| | 407 | ); |
| | 408 | |
| | 409 | CREATE TABLE "searches_results" ( |
| | 410 | "result_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, |
| | 411 | "search_id" INTEGER, |
| | 412 | "index" INTEGER NOT NULL, |
| | 413 | "title" TEXT NOT NULL, |
| | 414 | "details_url" TEXT NOT NULL, |
| | 415 | "thumbnail_image_url" TEXT NOT NULL, |
| | 416 | "image_url" TEXT NOT NULL |
| | 417 | ); |
| | 418 | |
| | 419 | CREATE INDEX "searches_provider_name" on searches (provider_name ASC); |
| | 420 | CREATE INDEX "searches_artist" on searches (artist ASC); |
| | 421 | CREATE INDEX "searches_album" on searches (album ASC); |
| | 422 | CREATE INDEX "searches_results_search_id" on searches_results (search_id ASC); |
| | 423 | |
| | 424 | CREATE TRIGGER delete_searches_results DELETE ON searches |
| | 425 | BEGIN |
| | 426 | DELETE FROM searches_results WHERE search_id = OLD.search_id; |
| | 427 | END; |
| | 428 | '); |
| | 429 | } |
| | 430 | |
| | 431 | $this->selectStmt = $this->dbh->prepare( |
| | 432 | "SELECT * FROM searches " . |
| | 433 | "LEFT JOIN searches_results AS sr ON sr.search_id = searches.search_id " . |
| | 434 | "WHERE provider_name = ? AND artist = ? AND album = ? ORDER BY `index`;" |
| | 435 | ); |
| | 436 | |
| | 437 | if (!$this->selectStmt) |
| | 438 | { |
| | 439 | echo "\nPDO::errorInfo():\n"; |
| | 440 | print_r($this->dbh->errorInfo()); |
| | 441 | } |
| | 442 | |
| | 443 | $this->insertSearchStmt = $this->dbh->prepare( |
| | 444 | "INSERT INTO searches (search_id, provider_name, artist, album, timestamp) " . |
| | 445 | "VALUES (NULL, ?, ?, ?, ?);" |
| | 446 | ); |
| | 447 | |
| | 448 | if (!$this->insertSearchStmt) |
| | 449 | { |
| | 450 | echo "\nPDO::errorInfo():\n"; |
| | 451 | print_r($this->dbh->errorInfo()); |
| | 452 | } |
| | 453 | |
| | 454 | $this->insertResultStmt = $this->dbh->prepare( |
| | 455 | "INSERT INTO searches_results (result_id, search_id, `index`, title, details_url, thumbnail_image_url, image_url) " . |
| | 456 | "VALUES (NULL, ?, ?, ?, ?, ?, ?);" |
| | 457 | ); |
| | 458 | |
| | 459 | if (!$this->insertResultStmt) |
| | 460 | { |
| | 461 | echo "\nPDO::errorInfo():\n"; |
| | 462 | print_r($this->dbh->errorInfo()); |
| | 463 | } |
| | 464 | } |
| | 465 | |
| | 466 | public function getCoverArtList($artist, $album, $limit = 0) |
| | 467 | { |
| | 468 | $listLimit = $limit; |
| | 469 | $list->results = array(); |
| | 470 | |
| | 471 | $coverArtProviderQueried = 0; |
| | 472 | |
| | 473 | foreach ($this->coverArtProviders as $provider) |
| | 474 | { |
| | 475 | $success = $this->selectStmt->execute(array($provider->name(), $artist, $album)); |
| | 476 | $rows = $this->selectStmt->fetchAll(); |
| | 477 | $resultsValid = false; |
| | 478 | |
| | 479 | if ($success && count($rows) > 0) |
| | 480 | { |
| | 481 | $resultsValid = $rows[0]["timestamp"] > time() - CACHE_EXPIRY_SECONDS; |
| | 482 | if (!$resultsValid) |
| | 483 | { |
| | 484 | //echo "Cached results expired, removing " . $rows[0][0]; |
| | 485 | $this->dbh->exec("DELETE FROM searches WHERE search_id = " . $rows[0][0] . ";"); |
| | 486 | } |
| | 487 | } |
| | 488 | |
| | 489 | if ($resultsValid) |
| | 490 | { |
| | 491 | //echo "Something was found in the cache..."; |
| | 492 | $coverArtList->results = array(); |
| | 493 | |
| | 494 | foreach ($rows as $row) |
| | 495 | { |
| | 496 | if (is_null($row["image_url"])) |
| | 497 | break; |
| | 498 | |
| | 499 | $coverArtItem = new CoverArtResult(); |
| | 500 | $coverArtItem->title = $row["title"]; |
| | 501 | $coverArtItem->detailsURL = $row["details_url"]; |
| | 502 | $coverArtItem->thumbnailImageURL = $row["thumbnail_image_url"]; |
| | 503 | $coverArtItem->imageURL = $row["image_url"]; |
| | 504 | $coverArtList->results[] = $coverArtItem; |
| | 505 | |
| | 506 | if ($limit > 0 && count($coverArtList->results) == $listLimit) |
| | 507 | break; |
| | 508 | } |
| | 509 | } |
| | 510 | else |
| | 511 | { |
| | 512 | //echo "Nothing found in the cache..."; |
| | 513 | $coverArtList = $provider->getCoverArtList($artist, $album, $listLimit); |
| | 514 | |
| | 515 | $this->dbh->beginTransaction(); |
| | 516 | |
| | 517 | if ($this->insertSearchStmt->execute(array($provider->name(), $artist, $album, time()))) |
| | 518 | { |
| | 519 | $searchID = $this->dbh->lastInsertId(); |
| | 520 | //echo "Search inserted: " . $searchID; |
| | 521 | |
| | 522 | foreach ($coverArtList->results as $index => $result) |
| | 523 | { |
| | 524 | $this->insertResultStmt->execute(array( |
| | 525 | $searchID, |
| | 526 | $index, |
| | 527 | $result->title, |
| | 528 | $result->detailsURL, |
| | 529 | $result->thumbnailImageURL, |
| | 530 | $result->imageURL |
| | 531 | )); |
| | 532 | } |
| | 533 | } |
| | 534 | |
| | 535 | $this->dbh->commit(); |
| | 536 | } |
| | 537 | |
| | 538 | $list->results = array_merge($list->results, $coverArtList->results); |
| | 539 | |
| | 540 | if ($limit > 0) |
| | 541 | { |
| | 542 | $listLimit = max(0, $listLimit - count($coverArtList->results)); |
| | 543 | if ($listLimit == 0) |
| | 544 | break; |
| | 545 | } |
| | 546 | |
| | 547 | if (count($coverArtList->results) > 0) |
| | 548 | ++$coverArtProviderQueried; |
| | 549 | |
| | 550 | if ($this->coverArtProviderQueryLimit > 0 && |
| | 551 | count($coverArtList->results) > 0 && |
| | 552 | $coverArtProviderQueried == $this->coverArtProviderQueryLimit) |
| | 553 | break; |
| | 554 | } |
| | 555 | |
| | 556 | return $list; |
| | 557 | } |