|
| 1 | +<?php |
| 2 | + |
| 3 | +class AuctionetBridge extends BridgeAbstract |
| 4 | +{ |
| 5 | + const NAME = 'Auctionet'; |
| 6 | + const URI = 'https://www.auctionet.com'; |
| 7 | + const DESCRIPTION = 'Fetches info about auction objects from Auctionet (an auction platform for many European auction houses)'; |
| 8 | + const MAINTAINER = 'Qluxzz'; |
| 9 | + const PARAMETERS = [[ |
| 10 | + 'category' => [ |
| 11 | + 'name' => 'Category', |
| 12 | + 'type' => 'list', |
| 13 | + 'values' => [ |
| 14 | + 'All categories' => '', |
| 15 | + 'Art' => [ |
| 16 | + 'All' => '25-art', |
| 17 | + 'Drawings' => '119-drawings', |
| 18 | + 'Engravings & Prints' => '27-engravings-prints', |
| 19 | + 'Other' => '30-other', |
| 20 | + 'Paintings' => '28-paintings', |
| 21 | + 'Photography' => '26-photography', |
| 22 | + 'Sculptures & Bronzes' => '29-sculptures-bronzes', |
| 23 | + ], |
| 24 | + 'Asiatica' => [ |
| 25 | + 'All' => '117-asiatica', |
| 26 | + ], |
| 27 | + 'Books, Maps & Manuscripts' => [ |
| 28 | + 'All' => '50-books-maps-manuscripts', |
| 29 | + 'Autographs & Manuscripts' => '206-autographs-manuscripts', |
| 30 | + 'Books' => '204-books', |
| 31 | + 'Maps' => '205-maps', |
| 32 | + 'Other' => '207-other', |
| 33 | + ], |
| 34 | + 'Carpets & Textiles' => [ |
| 35 | + 'All' => '35-carpets-textiles', |
| 36 | + 'Carpets' => '36-carpets', |
| 37 | + 'Textiles' => '37-textiles', |
| 38 | + ], |
| 39 | + 'Ceramics & Porcelain' => [ |
| 40 | + 'All' => '9-ceramics-porcelain', |
| 41 | + 'European' => '10-european', |
| 42 | + 'Oriental' => '11-oriental', |
| 43 | + 'Rest of the world' => '12-rest-of-the-world', |
| 44 | + 'Tableware' => '210-tableware', |
| 45 | + ], |
| 46 | + 'Clocks & Watches' => [ |
| 47 | + 'All' => '31-clocks-watches', |
| 48 | + 'Carriage & Miniature Clocks' => '258-carriage-miniature-clocks', |
| 49 | + 'Longcase clocks' => '32-longcase-clocks', |
| 50 | + 'Mantel clocks' => '33-mantel-clocks', |
| 51 | + 'Other clocks' => '34-other-clocks', |
| 52 | + 'Pocket & Stop Watches' => '110-pocket-stop-watches', |
| 53 | + 'Wall Clocks' => '127-wall-clocks', |
| 54 | + 'Wristwatches' => '15-wristwatches', |
| 55 | + ], |
| 56 | + 'Coins, Medals & Stamps' => [ |
| 57 | + 'All' => '46-coins-medals-stamps', |
| 58 | + 'Coins' => '128-coins', |
| 59 | + 'Orders & Medals' => '135-orders-medals', |
| 60 | + 'Other' => '131-other', |
| 61 | + 'Stamps' => '136-stamps', |
| 62 | + ], |
| 63 | + 'Folk art' => [ |
| 64 | + 'All' => '58-folk-art', |
| 65 | + 'Bowls & Boxes' => '121-bowls-boxes', |
| 66 | + 'Furniture' => '122-furniture', |
| 67 | + 'Other' => '123-other', |
| 68 | + 'Tools & Gears' => '120-tools-gears', |
| 69 | + ], |
| 70 | + 'Furniture' => [ |
| 71 | + 'All' => '16-furniture', |
| 72 | + 'Armchairs & Chairs' => '18-armchairs-chairs', |
| 73 | + 'Chests of drawers' => '24-chests-of-drawers', |
| 74 | + 'Cupboards, Cabinets & Shelves' => '23-cupboards-cabinets-shelves', |
| 75 | + 'Dining room furniture' => '22-dining-room-furniture', |
| 76 | + 'Garden' => '21-garden', |
| 77 | + 'Other' => '17-other', |
| 78 | + 'Sofas & seatings' => '20-sofas-seatings', |
| 79 | + 'Tables' => '19-tables', |
| 80 | + ], |
| 81 | + 'Glass' => [ |
| 82 | + 'All' => '6-glass', |
| 83 | + 'Art glass' => '208-art-glass', |
| 84 | + 'Other' => '8-other', |
| 85 | + 'Tableware' => '7-tableware', |
| 86 | + 'Utility glass' => '209-utility-glass', |
| 87 | + ], |
| 88 | + 'Jewellery & Gemstones' => [ |
| 89 | + 'All' => '13-jewellery-gemstones', |
| 90 | + 'Alliance rings' => '113-alliance-rings', |
| 91 | + 'Bracelets' => '106-bracelets', |
| 92 | + 'Brooches & Pendants' => '107-brooches-pendants', |
| 93 | + 'Costume Jewellery' => '259-costume-jewellery', |
| 94 | + 'Cufflinks & Tie Pins' => '111-cufflinks-tie-pins', |
| 95 | + 'Ear studs' => '116-ear-studs', |
| 96 | + 'Earrings' => '115-earrings', |
| 97 | + 'Gemstones' => '48-gemstones', |
| 98 | + 'Jewellery' => '14-jewellery', |
| 99 | + 'Jewellery Suites' => '109-jewellery-suites', |
| 100 | + 'Necklace' => '104-necklace', |
| 101 | + 'Other' => '118-other', |
| 102 | + 'Rings' => '112-rings', |
| 103 | + 'Signet rings' => '105-signet-rings', |
| 104 | + 'Solitaire rings' => '114-solitaire-rings', |
| 105 | + ], |
| 106 | + 'Licence weapons' => [ |
| 107 | + 'All' => '59-licence-weapons', |
| 108 | + 'Combi/Combo' => '63-combi-combo', |
| 109 | + 'Double express rifles' => '60-double-express-rifles', |
| 110 | + 'Rifles' => '61-rifles', |
| 111 | + 'Shotguns' => '62-shotguns', |
| 112 | + ], |
| 113 | + 'Lighting & Lamps' => [ |
| 114 | + 'All' => '1-lighting-lamps', |
| 115 | + 'Candlesticks' => '4-candlesticks', |
| 116 | + 'Ceiling lights' => '3-ceiling-lights', |
| 117 | + 'Chandeliers' => '203-chandeliers', |
| 118 | + 'Floor lights' => '2-floor-lights', |
| 119 | + 'Other lighting' => '5-other-lighting', |
| 120 | + 'Table Lamps' => '125-table-lamps', |
| 121 | + 'Wall Lights' => '124-wall-lights', |
| 122 | + ], |
| 123 | + 'Mirrors' => [ |
| 124 | + 'All' => '42-mirrors', |
| 125 | + ], |
| 126 | + 'Miscellaneous' => [ |
| 127 | + 'All' => '43-miscellaneous', |
| 128 | + 'Fishing equipment' => '54-fishing-equipment', |
| 129 | + 'Miscellaneous' => '47-miscellaneous', |
| 130 | + 'Modern Tools' => '133-modern-tools', |
| 131 | + 'Modern consumer electronics' => '52-modern-consumer-electronics', |
| 132 | + 'Musical instruments' => '51-musical-instruments', |
| 133 | + 'Technica & Nautica' => '45-technica-nautica', |
| 134 | + ], |
| 135 | + 'Photo, Cameras & Lenses' => [ |
| 136 | + 'All' => '57-photo-cameras-lenses', |
| 137 | + 'Cameras & accessories' => '71-cameras-accessories', |
| 138 | + 'Optics' => '66-optics', |
| 139 | + 'Other' => '72-other', |
| 140 | + ], |
| 141 | + 'Silver & Metals' => [ |
| 142 | + 'All' => '38-silver-metals', |
| 143 | + 'Other metals' => '40-other-metals', |
| 144 | + 'Pewter, Brass & Copper' => '41-pewter-brass-copper', |
| 145 | + 'Silver' => '39-silver', |
| 146 | + 'Silver plated' => '213-silver-plated', |
| 147 | + ], |
| 148 | + 'Toys' => [ |
| 149 | + 'All' => '44-toys', |
| 150 | + 'Comics' => '211-comics', |
| 151 | + 'Toys' => '212-toys', |
| 152 | + ], |
| 153 | + 'Tribal art' => [ |
| 154 | + 'All' => '134-tribal-art', |
| 155 | + ], |
| 156 | + 'Vehicles, Boats & Parts' => [ |
| 157 | + 'All' => '249-vehicles-boats-parts', |
| 158 | + 'Automobilia & Transport' => '255-automobilia-transport', |
| 159 | + 'Bicycles' => '132-bicycles', |
| 160 | + 'Boats & Accessories' => '250-boats-accessories', |
| 161 | + 'Car parts' => '253-car-parts', |
| 162 | + 'Cars' => '215-cars', |
| 163 | + 'Moped parts' => '254-moped-parts', |
| 164 | + 'Mopeds' => '216-mopeds', |
| 165 | + 'Motorcycle parts' => '252-motorcycle-parts', |
| 166 | + 'Motorcycles' => '251-motorcycles', |
| 167 | + 'Other' => '256-other', |
| 168 | + ], |
| 169 | + 'Vintage & Designer Fashion' => [ |
| 170 | + 'All' => '49-vintage-designer-fashion', |
| 171 | + ], |
| 172 | + 'Weapons & Militaria' => [ |
| 173 | + 'All' => '137-weapons-militaria', |
| 174 | + 'Airguns' => '257-airguns', |
| 175 | + 'Armour & Uniform' => '138-armour-uniform', |
| 176 | + 'Edged weapons' => '130-edged-weapons', |
| 177 | + 'Guns & Rifles' => '129-guns-rifles', |
| 178 | + 'Other' => '214-other', |
| 179 | + ], |
| 180 | + 'Wine, Port & Spirits' => [ |
| 181 | + 'All' => '170-wine-port-spirits', |
| 182 | + ], |
| 183 | + ] |
| 184 | + ], |
| 185 | + 'sort_order' => [ |
| 186 | + 'name' => 'Sort order', |
| 187 | + 'type' => 'list', |
| 188 | + 'values' => [ |
| 189 | + 'Most bids' => 'bids_count_desc', |
| 190 | + 'Lowest bid' => 'bid_asc', |
| 191 | + 'Highest bid' => 'bid_desc', |
| 192 | + 'Last bid on' => 'bid_on', |
| 193 | + 'Ending soonest' => 'end_asc_active', |
| 194 | + 'Lowest estimate' => 'estimate_asc', |
| 195 | + 'Highest estimate' => 'estimate_desc', |
| 196 | + 'Recently added' => 'recent' |
| 197 | + ], |
| 198 | + ], |
| 199 | + 'country' => [ |
| 200 | + 'name' => 'Country', |
| 201 | + 'type' => 'list', |
| 202 | + 'values' => [ |
| 203 | + 'All' => '', |
| 204 | + 'Denmark' => 'DK', |
| 205 | + 'Finland' => 'FI', |
| 206 | + 'Germany' => 'DE', |
| 207 | + 'Spain' => 'ES', |
| 208 | + 'Sweden' => 'SE', |
| 209 | + 'United Kingdom' => 'GB' |
| 210 | + ] |
| 211 | + ], |
| 212 | + 'language' => [ |
| 213 | + 'name' => 'Language', |
| 214 | + 'type' => 'list', |
| 215 | + 'values' => [ |
| 216 | + 'English' => 'en', |
| 217 | + 'Español' => 'es', |
| 218 | + 'Deutsch' => 'de', |
| 219 | + 'Svenska' => 'sv', |
| 220 | + 'Dansk' => 'da', |
| 221 | + 'Suomi' => 'fi', |
| 222 | + ], |
| 223 | + ], |
| 224 | + ]]; |
| 225 | + |
| 226 | + const CACHE_TIMEOUT = 3600; // 1 hour |
| 227 | + |
| 228 | + private $title; |
| 229 | + |
| 230 | + public function collectData() |
| 231 | + { |
| 232 | + // Each page contains 48 auctions |
| 233 | + // So we fetch 10 pages so we decrease the likelihood |
| 234 | + // of missing auctions between feed refreshes |
| 235 | + |
| 236 | + // Fetch first page and use that to get title |
| 237 | + { |
| 238 | + $url = $this->getUrl(1); |
| 239 | + $data = getContents($url); |
| 240 | + |
| 241 | + $title = $this->getDocumentTitle($data); |
| 242 | + |
| 243 | + $this->items = array_merge($this->items, $this->parsePageData($data)); |
| 244 | + } |
| 245 | + |
| 246 | + // Fetch remaining pages |
| 247 | + for ($page = 2; $page <= 10; $page++) { |
| 248 | + $url = $this->getUrl($page); |
| 249 | + |
| 250 | + $data = getContents($url); |
| 251 | + |
| 252 | + $this->items = array_merge($this->items, $this->parsePageData($data)); |
| 253 | + } |
| 254 | + } |
| 255 | + |
| 256 | + public function getName() |
| 257 | + { |
| 258 | + return $this->title ?: parent::getName(); |
| 259 | + } |
| 260 | + |
| 261 | + |
| 262 | + /* HELPERS */ |
| 263 | + |
| 264 | + private function getUrl($page) |
| 265 | + { |
| 266 | + $category = $this->getInput('category'); |
| 267 | + $language = $this->getInput('language'); |
| 268 | + $sort_order = $this->getInput('sort_order'); |
| 269 | + $country = $this->getInput('country'); |
| 270 | + |
| 271 | + $url = self::URI . '/' . $language . '/search'; |
| 272 | + |
| 273 | + if ($category) { |
| 274 | + $url = $url . '/' . $category; |
| 275 | + } |
| 276 | + |
| 277 | + $query = []; |
| 278 | + $query['page'] = $page; |
| 279 | + |
| 280 | + if ($sort_order) { |
| 281 | + $query['order'] = $sort_order; |
| 282 | + } |
| 283 | + |
| 284 | + if ($country) { |
| 285 | + $query['country_code'] = $country; |
| 286 | + } |
| 287 | + |
| 288 | + if (count($query) > 0) { |
| 289 | + $url = $url . '?' . http_build_query($query); |
| 290 | + } |
| 291 | + |
| 292 | + return $url; |
| 293 | + } |
| 294 | + |
| 295 | + private function getDocumentTitle($data) |
| 296 | + { |
| 297 | + $title_elem = '<title>'; |
| 298 | + $title_elem_length = strlen($title_elem); |
| 299 | + $title_start = strpos($data, $title_elem); |
| 300 | + $title_end = strpos($data, '</title>', $title_start); |
| 301 | + $title_length = $title_end - $title_start + strlen($title_elem); |
| 302 | + $title = substr($data, $title_start + strlen($title_elem), $title_length); |
| 303 | + |
| 304 | + return $title; |
| 305 | + } |
| 306 | + |
| 307 | + /** |
| 308 | + * The auction items data is included in the HTML document |
| 309 | + * as a HTML entities encoded JSON structure |
| 310 | + * which is used to hydrate the React component for the list of auctions |
| 311 | + */ |
| 312 | + private function parsePageData($data) |
| 313 | + { |
| 314 | + $key = 'data-react-props="'; |
| 315 | + $keyLength = strlen($key); |
| 316 | + |
| 317 | + $start = strpos($data, $key); |
| 318 | + $end = strpos($data, '"', $start + strlen($key)); |
| 319 | + $length = $end - ($start + $keyLength); |
| 320 | + |
| 321 | + $jsonString = substr($data, $start + $keyLength, $length); |
| 322 | + |
| 323 | + $jsonData = json_decode(htmlspecialchars_decode($jsonString), false); |
| 324 | + |
| 325 | + $items = []; |
| 326 | + |
| 327 | + foreach ($jsonData->{'items'} as $item) { |
| 328 | + $title = $item->{'longTitle'}; |
| 329 | + $relative_url = $item->{'url'}; |
| 330 | + $images = $item->{'imageUrls'}; |
| 331 | + $id = $item->{'auctionId'}; |
| 332 | + |
| 333 | + $items[] = [ |
| 334 | + 'title' => $title, |
| 335 | + 'uri' => self::URI . $relative_url, |
| 336 | + 'uid' => $id, |
| 337 | + 'content' => count($images) > 0 ? "<img src='$images[0]'/><br/>$title" : $title, |
| 338 | + 'enclosures' => array_slice($images, 1), |
| 339 | + ]; |
| 340 | + } |
| 341 | + |
| 342 | + return $items; |
| 343 | + } |
| 344 | +} |
0 commit comments