From 4facbf32e3e246b9b93c1d086edac3cbde4dddee Mon Sep 17 00:00:00 2001 From: LogMANOriginal Date: Sat, 21 Jul 2018 15:25:13 +0200 Subject: [PATCH] [InstructableBridge] Add new bridge (#724) This commit adds a new bridge for http://www.instructables.com. This bridge currently supports fetching content by category (all categories available 200+), using available filters (featured, recent, popular, views, contest winners). --- bridges/InstructablesBridge.php | 370 ++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 bridges/InstructablesBridge.php diff --git a/bridges/InstructablesBridge.php b/bridges/InstructablesBridge.php new file mode 100644 index 0000000..05f1a91 --- /dev/null +++ b/bridges/InstructablesBridge.php @@ -0,0 +1,370 @@ + array( + 'category' => array( + 'name' => 'Category', + 'type' => 'list', + 'required' => true, + 'values' => array( + 'Play' => array( + 'All' => '/play/', + 'KNEX' => '/play/knex/', + 'Offbeat' => '/play/offbeat/', + 'Lego' => '/play/lego/', + 'Airsoft' => '/play/airsoft/', + 'Card Games' => '/play/card-games/', + 'Guitars' => '/play/guitars/', + 'Instruments' => '/play/instruments/', + 'Magic Tricks' => '/play/magic-tricks/', + 'Minecraft' => '/play/minecraft/', + 'Music' => '/play/music/', + 'Nerf' => '/play/nerf/', + 'Nintendo' => '/play/nintendo/', + 'Office Supplies' => '/play/office-supplies/', + 'Paintball' => '/play/paintball/', + 'Paper Airplanes' => '/play/paper-airplanes/', + 'Party Tricks' => '/play/party-tricks/', + 'PlayStation' => '/play/playstation/', + 'Pranks and Humor' => '/play/pranks-and-humor/', + 'Puzzles' => '/play/puzzles/', + 'Siege Engines' => '/play/siege-engines/', + 'Sports' => '/play/sports/', + 'Table Top' => '/play/table-top/', + 'Toys' => '/play/toys/', + 'Video Games' => '/play/video-games/', + 'Wii' => '/play/wii/', + 'Xbox' => '/play/xbox/', + 'Yo-Yo' => '/play/yo-yo/', + ), + 'Craft' => array( + 'All' => '/craft/', + 'Art' => '/craft/art/', + 'Sewing' => '/craft/sewing/', + 'Paper' => '/craft/paper/', + 'Jewelry' => '/craft/jewelry/', + 'Fashion' => '/craft/fashion/', + 'Books & Journals' => '/craft/books-and-journals/', + 'Cards' => '/craft/cards/', + 'Clay' => '/craft/clay/', + 'Duct Tape' => '/craft/duct-tape/', + 'Embroidery' => '/craft/embroidery/', + 'Felt' => '/craft/felt/', + 'Fiber Arts' => '/craft/fiber-arts/', + 'Gifts & Wrapping' => '/craft/gifts-and-wrapping/', + 'Knitting & Crocheting' => '/craft/knitting-and-crocheting/', + 'Leather' => '/craft/leather/', + 'Mason Jars' => '/craft/mason-jars/', + 'No-Sew' => '/craft/no-sew/', + 'Parties & Weddings' => '/craft/parties-and-weddings/', + 'Print Making' => '/craft/print-making/', + 'Soap' => '/craft/soap/', + 'Wallets' => '/craft/wallets/', + ), + 'Technology' => array( + 'All' => '/technology/', + 'Electronics' => '/technology/electronics/', + 'Arduino' => '/technology/arduino/', + 'Photography' => '/technology/photography/', + 'Leds' => '/technology/leds/', + 'Science' => '/technology/science/', + 'Reuse' => '/technology/reuse/', + 'Apple' => '/technology/apple/', + 'Computers' => '/technology/computers/', + '3D Printing' => '/technology/3D-Printing/', + 'Robots' => '/technology/robots/', + 'Art' => '/technology/art/', + 'Assistive Tech' => '/technology/assistive-technology/', + 'Audio' => '/technology/audio/', + 'Clocks' => '/technology/clocks/', + 'CNC' => '/technology/cnc/', + 'Digital Graphics' => '/technology/digital-graphics/', + 'Gadgets' => '/technology/gadgets/', + 'Kits' => '/technology/kits/', + 'Laptops' => '/technology/laptops/', + 'Lasers' => '/technology/lasers/', + 'Linux' => '/technology/linux/', + 'Microcontrollers' => '/technology/microcontrollers/', + 'Microsoft' => '/technology/microsoft/', + 'Mobile' => '/technology/mobile/', + 'Raspberry Pi' => '/technology/raspberry-pi/', + 'Remote Control' => '/technology/remote-control/', + 'Sensors' => '/technology/sensors/', + 'Software' => '/technology/software/', + 'Soldering' => '/technology/soldering/', + 'Speakers' => '/technology/speakers/', + 'Steampunk' => '/technology/steampunk/', + 'Tools' => '/technology/tools/', + 'USB' => '/technology/usb/', + 'Wearables' => '/technology/wearables/', + 'Websites' => '/technology/websites/', + 'Wireless' => '/technology/wireless/', + ), + 'Workshop' => array( + 'All' => '/workshop/', + 'Woodworking' => '/workshop/woodworking/', + 'Tools' => '/workshop/tools/', + 'Gardening' => '/workshop/gardening/', + 'Cars' => '/workshop/cars/', + 'Metalworking' => '/workshop/metalworking/', + 'Cardboard' => '/workshop/cardboard/', + 'Electric Vehicles' => '/workshop/electric-vehicles/', + 'Energy' => '/workshop/energy/', + 'Furniture' => '/workshop/furniture/', + 'Home Improvement' => '/workshop/home-improvement/', + 'Home Theater' => '/workshop/home-theater/', + 'Hydroponics' => '/workshop/hydroponics/', + 'Laser Cutting' => '/workshop/laser-cutting/', + 'Lighting' => '/workshop/lighting/', + 'Molds & Casting' => '/workshop/molds-and-casting/', + 'Motorcycles' => '/workshop/motorcycles/', + 'Organizing' => '/workshop/organizing/', + 'Pallets' => '/workshop/pallets/', + 'Repair' => '/workshop/repair/', + 'Shelves' => '/workshop/shelves/', + 'Solar' => '/workshop/solar/', + 'Workbenches' => '/workshop/workbenches/', + ), + 'Home' => array( + 'All' => '/home/', + 'Halloween' => '/home/halloween/', + 'Decorating' => '/home/decorating/', + 'Organizing' => '/home/organizing/', + 'Pets' => '/home/pets/', + 'Life Hacks' => '/home/life-hacks/', + 'Beauty' => '/home/beauty/', + 'Christmas' => '/home/christmas/', + 'Cleaning' => '/home/cleaning/', + 'Education' => '/home/education/', + 'Finances' => '/home/finances/', + 'Gardening' => '/home/gardening/', + 'Green' => '/home/green/', + 'Health' => '/home/health/', + 'Hiding Places' => '/home/hiding-places/', + 'Holidays' => '/home/holidays/', + 'Homesteading' => '/home/homesteading/', + 'Kids' => '/home/kids/', + 'Kitchen' => '/home/kitchen/', + 'Life Skills' => '/home/life-skills/', + 'Parenting' => '/home/parenting/', + 'Pest Control' => '/home/pest-control/', + 'Relationships' => '/home/relationships/', + 'Reuse' => '/home/reuse/', + 'Travel' => '/home/travel/', + ), + 'Outside' => array( + 'All' => '/outside/', + 'Bikes' => '/outside/bikes/', + 'Survival' => '/outside/survival/', + 'Backyard' => '/outside/backyard/', + 'Beach' => '/outside/beach/', + 'Birding' => '/outside/birding/', + 'Boats' => '/outside/boats/', + 'Camping' => '/outside/camping/', + 'Climbing' => '/outside/climbing/', + 'Fire' => '/outside/fire/', + 'Fishing' => '/outside/fishing/', + 'Hunting' => '/outside/hunting/', + 'Kites' => '/outside/kites/', + 'Knives' => '/outside/knives/', + 'Knots' => '/outside/knots/', + 'Paracord' => '/outside/paracord/', + 'Rockets' => '/outside/rockets/', + 'Skateboarding' => '/outside/skateboarding/', + 'Snow' => '/outside/snow/', + 'Water' => '/outside/water/', + ), + 'Food' => array( + 'All' => '/food/', + 'Dessert' => '/food/dessert/', + 'Snacks & Appetizers' => '/food/snacks-and-appetizers/', + 'Bacon' => '/food/bacon/', + 'BBQ & Grilling' => '/food/bbq-and-grilling/', + 'Beverages' => '/food/beverages/', + 'Bread' => '/food/bread/', + 'Breakfast' => '/food/breakfast/', + 'Cake' => '/food/cake/', + 'Candy' => '/food/candy/', + 'Canning & Preserves' => '/food/canning-and-preserves/', + 'Cocktails & Mocktails' => '/food/cocktails-and-mocktails/', + 'Coffee' => '/food/coffee/', + 'Cookies' => '/food/cookies/', + 'Cupcakes' => '/food/cupcakes/', + 'Homebrew' => '/food/homebrew/', + 'Main Course' => '/food/main-course/', + 'Pasta' => '/food/pasta/', + 'Pie' => '/food/pie/', + 'Pizza' => '/food/pizza/', + 'Salad' => '/food/salad/', + 'Sandwiches' => '/food/sandwiches/', + 'Soups & Stews' => '/food/soups-and-stews/', + 'Vegetarian & Vegan' => '/food/vegetarian-and-vegan/', + ), + 'Costumes' => array( + 'All' => '/costumes/', + 'Props' => '/costumes/props-and-accessories/', + 'Animals' => '/costumes/animals/', + 'Comics' => '/costumes/comics/', + 'Fantasy' => '/costumes/fantasy/', + 'For Kids' => '/costumes/for-kids/', + 'For Pets' => '/costumes/for-pets/', + 'Funny' => '/costumes/funny/', + 'Games' => '/costumes/games/', + 'Historic & Futuristic' => '/costumes/historic-and-futuristic/', + 'Makeup' => '/costumes/makeup/', + 'Masks' => '/costumes/masks/', + 'Scary' => '/costumes/scary/', + 'TV & Movies' => '/costumes/tv-and-movies/', + 'Weapons & Armor' => '/costumes/weapons-and-armor/', + ) + ), + 'title' => 'Select your category (required)', + 'defaultValue' => 'Technology' + ), + 'filter' => array( + 'name' => 'Filter', + 'type' => 'list', + 'required' => true, + 'values' => array( + 'Featured' => ' ', + 'Recent' => 'recent/', + 'Popular' => 'popular/', + 'Views' => 'views/', + 'Contest Winners' => 'winners/' + ), + 'title' => 'Select a filter', + 'defaultValue' => 'Featured' + ) + ) + ); + + private $uri; + + public function collectData() { + // Enable the following line to get the category list (dev mode) + // $this->listCategories(); + + $this->uri = static::URI; + + switch($this->queriedContext) { + case 'Category': $this->uri .= $this->getInput('category') . $this->getInput('filter'); + } + + $html = getSimpleHTMLDOM($this->uri) + or returnServerError('Error loading category ' . $this->uri); + + foreach($html->find('ul.explore-covers-list li') as $cover) { + $item = array(); + + $item['uri'] = static::URI . $cover->find('a.cover-image', 0)->href; + $item['title'] = $cover->find('.title', 0)->innertext; + $item['author'] = $this->getCategoryAuthor($cover); + $item['content'] = 'src + . '>'; + + $image = str_replace('.RECTANGLE1', '.LARGE', $cover->find('a.cover-image img', 0)->src); + $item['enclosures'] = [$image]; + + $this->items[] = $item; + } + } + + public function getName() { + if(!is_null($this->getInput('category')) + && !is_null($this->getInput('filter'))) { + foreach(self::PARAMETERS[$this->queriedContext]['category']['values'] as $key => $value) { + $subcategory = array_search($this->getInput('category'), $value); + + if($subcategory !== false) + break; + } + + $filter = array_search( + $this->getInput('filter'), + self::PARAMETERS[$this->queriedContext]['filter']['values'] + ); + + return $subcategory . ' (' . $filter . ') - ' . static::NAME; + } + + return parent::getName(); + } + + public function getURI() { + if(!is_null($this->getInput('category')) + && !is_null($this->getInput('filter'))) { + return $this->uri; + } + + return parent::getURI(); + } + + /** + * Returns a list of categories for development purposes (used to build the + * parameters list) + */ + private function listCategories(){ + // Use arbitrary category to receive full list + $html = getSimpleHTMLDOM(self::URI . '/technology/'); + + foreach($html->find('.channel a') as $channel) { + $name = html_entity_decode(trim($channel->innertext)); + + // Remove unwanted entities + $name = str_replace("'", '', $name); + $name = str_replace(''', '', $name); + + $uri = $channel->href; + + $category = explode('/', $uri)[1]; + + if(!isset($categories) + || !array_key_exists($category, $categories) + || !in_array($uri, $categories[$category])) + $categories[$category][$name] = $uri; + } + + // Build PHP array manually + foreach($categories as $key => $value) { + $name = ucfirst($key); + echo "'{$name}' => array(\n"; + echo "\t'All' => '/{$key}/',\n"; + foreach($value as $name => $uri) { + echo "\t'{$name}' => '{$uri}',\n"; + } + echo "),\n"; + } + + die; + } + + /** + * Returns the author as anchor for a given cover. + */ + private function getCategoryAuthor($cover) { + return 'href + . '>' + . $cover->find('span.author a', 0)->innertext + . ''; + } +}