Merge pull request #304 from eai04191/feature/resolver-hentai-foundry

HentaiFoundryResolverを追加
This commit is contained in:
shibafu 2019-12-10 23:40:01 +09:00 committed by GitHub
commit 6577a032e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 478 additions and 1 deletions

View File

@ -0,0 +1,56 @@
<?php
namespace App\MetadataResolver;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use Symfony\Component\DomCrawler\Crawler;
class HentaiFoundryResolver implements Resolver
{
/**
* @var Client
*/
private $client;
/**
* @var OGPResolver
*/
private $ogpResolver;
public function __construct(Client $client, OGPResolver $ogpResolver)
{
$this->client = $client;
$this->ogpResolver = $ogpResolver;
}
private function nbsp2space(string $string): string
{
return str_replace("\xc2\xa0", ' ', $string);
}
private function br2nl(string $string): string
{
return str_replace('<br>', PHP_EOL, $string);
}
public function resolve(string $url): Metadata
{
$res = $this->client->get(
http_build_url($url, ['query' => 'enterAgree=1']),
['cookies' => new CookieJar()]
);
$metadata = new Metadata();
$crawler = new Crawler((string) $res->getBody());
$author = $crawler->filter('#picBox .boxtitle a')->text();
$description = trim(strip_tags($this->nbsp2space($this->br2nl($crawler->filter('.picDescript')->html()))));
$metadata->title = $crawler->filter('#picBox .boxtitle .imageTitle')->text();
$metadata->description = 'by ' . $author . PHP_EOL . $description;
$metadata->image = 'https:' . $crawler->filter('img[src^="//picture"]')->attr('src');
$metadata->tags = $crawler->filter('a[rel="tag"]')->extract('_text');
return $metadata;
}
}

View File

@ -33,6 +33,7 @@ class MetadataResolver implements Resolver
'~store\.steampowered\.com/app/\d+~' => SteamResolver::class, '~store\.steampowered\.com/app/\d+~' => SteamResolver::class,
'~www\.xtube\.com/video-watch/.*-\d+$~'=> XtubeResolver::class, '~www\.xtube\.com/video-watch/.*-\d+$~'=> XtubeResolver::class,
'~ss\.kb10uy\.org/posts/\d+$~' => Kb10uyShortStoryServerResolver::class, '~ss\.kb10uy\.org/posts/\d+$~' => Kb10uyShortStoryServerResolver::class,
'~www\.hentai-foundry\.com/pictures/user/.+/\d+/.+~'=> HentaiFoundryResolver::class,
]; ];
public $mimeTypes = [ public $mimeTypes = [

View File

@ -10,6 +10,7 @@
"doctrine/dbal": "^2.9", "doctrine/dbal": "^2.9",
"fideloper/proxy": "~3.3", "fideloper/proxy": "~3.3",
"guzzlehttp/guzzle": "^6.3", "guzzlehttp/guzzle": "^6.3",
"jakeasmith/http_build_url": "^1.0",
"laravel/framework": "5.5.*", "laravel/framework": "5.5.*",
"laravel/tinker": "~1.0", "laravel/tinker": "~1.0",
"misd/linkify": "^1.1", "misd/linkify": "^1.1",

35
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "28abd730d4572663d10ae815393c73cd", "content-hash": "b6dfb80c350a7276bb2513a1aeb3d602",
"packages": [ "packages": [
{ {
"name": "anhskohbo/no-captcha", "name": "anhskohbo/no-captcha",
@ -806,6 +806,39 @@
], ],
"time": "2019-07-01T23:21:34+00:00" "time": "2019-07-01T23:21:34+00:00"
}, },
{
"name": "jakeasmith/http_build_url",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/jakeasmith/http_build_url.git",
"reference": "93c273e77cb1edead0cf8bcf8cd2003428e74e37"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jakeasmith/http_build_url/zipball/93c273e77cb1edead0cf8bcf8cd2003428e74e37",
"reference": "93c273e77cb1edead0cf8bcf8cd2003428e74e37",
"shasum": ""
},
"type": "library",
"autoload": {
"files": [
"src/http_build_url.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jake A. Smith",
"email": "theman@jakeasmith.com"
}
],
"description": "Provides functionality for http_build_url() to environments without pecl_http.",
"time": "2017-05-01T15:36:40+00:00"
},
{ {
"name": "jakub-onderka/php-console-color", "name": "jakub-onderka/php-console-color",
"version": "v0.2", "version": "v0.2",

View File

@ -0,0 +1,36 @@
<?php
namespace Tests\Unit\MetadataResolver;
use App\MetadataResolver\HentaiFoundryResolver;
use Tests\TestCase;
class HentaiFoundryResolverTest extends TestCase
{
use CreateMockedResolver;
public function setUp()
{
parent::setUp();
if (!$this->shouldUseMock()) {
sleep(1);
}
}
public function test()
{
$responseText = file_get_contents(__DIR__ . '/../../fixture/HentaiFoundry/illust.html');
$this->createResolver(HentaiFoundryResolver::class, $responseText);
$metadata = $this->resolver->resolve('https://www.hentai-foundry.com/pictures/user/DevilHS/723498/Witchcraft');
$this->assertSame('Witchcraft', $metadata->title);
$this->assertSame('by DevilHS' . PHP_EOL . 'gift for Liru', $metadata->description);
$this->assertEquals(['witch', 'futa'], $metadata->tags);
$this->assertSame('https://pictures.hentai-foundry.com/d/DevilHS/723498/DevilHS-723498-Witchcraft.png', $metadata->image);
if ($this->shouldUseMock()) {
$this->assertSame('https://www.hentai-foundry.com/pictures/user/DevilHS/723498/Witchcraft?enterAgree=1', (string) $this->handler->getLastRequest()->getUri());
}
}
}

350
tests/fixture/HentaiFoundry/illust.html vendored Normal file
View File

@ -0,0 +1,350 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="//img.hentai-foundry.com/themes/Dark/css/default.css?ver=1497240029" title="Default CSS" />
<link rel="shortcut icon" href="//img.hentai-foundry.com/themes/Dark/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml"
title="Search Hentai Foundry"
href="/search/OpenSearchDescription"
/>
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js">
</script>
<![endif]-->
<meta name="description" content="gift for Liru" /> <meta name="keywords" content="witch futa" />
<link title="Comments Feed" rel="alternate" type="application/atom+xml" href="/feed/PictureComments/id/723498" />
<link rel="stylesheet" type="text/css" href="//img.hentai-foundry.com/themes/default/js/qtip2.2.1/jquery.qtip.min.css" />
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript" src="//img.hentai-foundry.com/themes/default/js/qtip2.2.1/jquery.qtip.min.js" async="async"></script>
<title>Witchcraft by DevilHS - Hentai Foundry</title>
<script type="text/javascript" src="//img.hentai-foundry.com/themes/default/js/util.js?ver=20170507"></script>
<link rel="meta" href="//img.hentai-foundry.com/themes/Hentai/labels.rdf" type="application/rdf+xml" title="ICRA labels" />
<meta http-equiv="PICS-Label" content='(PICS-1.1 "http://www.icra.org/pics/vocabularyv03/" l gen true for "http://hentai-foundry.com" r (n 3 s 3 v 0 l 2 oa 0 ob 0 oc 0 od 0 oe 0 of 0 og 0 oh 0 c 3) gen true for "http://www.hentai-foundry.com" r (n 3 s 3 v 0 l 2 oa 0 ob 0 oc 0 od 0 oe 0 of 0 og 0 oh 0 c 3))' />
<meta http-equiv="PICS-Label" content='(PICS-1.1 "http://www.classify.org/safesurf/" L gen true for "http://www.hentai-foundry.com/" r (SS~~000 9 SS~~001 5 SS~~002 5 SS~~003 5 SS~~004 9 SS~~005 5 SS~~007 5 SS~~008 5 SS~~009 9 SS~~00A 5))' />
<meta name="RATING" content="RTA-5042-1996-1400-1577-RTA" />
<link rel="stylesheet" type="text/css" href="//img.hentai-foundry.com/themes/default/css/activebar.css" />
<script type="text/javascript" src="//img.hentai-foundry.com/themes/default/js/activebar.js"></script>
<script type="text/javascript">
var noadblocker=false;
</script>
<script type="text/javascript" src="//img.hentai-foundry.com/themes/default/js/ads.js"></script>
<script type="text/javascript">
if(!noadblocker)
document.addEventListener("DOMContentLoaded", function() { setTimeout(adBar, 1000) } );
</script>
</head>
<body id="pictures_view">
<header>
<a href="/site/index">
<img src="//img.hentai-foundry.com/themes/Dark/images/logo.png" border="0" alt="Logo" title="Logo" id="logo"/>
</a>
<div id="searchBox">
<form action="/search/index" method="get">
<input type="text" name="query" />
<input type="submit" value="Search" />
<br />
<a class="navlink" href="/search/index">Advanced Search</a> </form>
</div>
<div id='headerLogin'>
<form action="/site/login" method="post">
<input type="hidden" value="SHpiT1dzOXpYRU50OVZzRXZOSWp-dzZnTTlmV3U1ck16J9k70kDwVW5YeySDxE7l5lbXi0wmIwy8jihTTFdr3w==" name="YII_CSRF_TOKEN" /> Username <input type="text" name="LoginForm[username]" /> &nbsp;
Password <input type="password" name="LoginForm[password]" /> &nbsp;
<input type="submit" value="Login" />
<br />
Remember <input type="checkbox" value="1" name="LoginForm[rememberMe]" style="background: #676573;" />
&nbsp; <a class='navlink' href="/users/create">Register</a> &nbsp;
| &nbsp; <a class='navlink' href="/users/LostPassword">Forgot your password?</a>
</form>
</div>
</header>
<nav id="mainmenu">
<input id="menuToggleCheckbox" type="checkbox" />
<label for="menuToggleCheckbox" id="menuToggle">&#8801;<span>MENU</span></label>
<div id="filtersButton"><a onClick="ths = $(this); jQuery(&#039;#FilterBox&#039;).css({top: ths.offset().top, left: ths.offset().left + ths.outerWidth() + 10}); jQuery(&#039;#FilterBox&#039;).toggle(500); return false;" href="#"><i class="fa fa-list"></i> FILTERS</a></div><aside class="box lvl1" id="FilterBox">
<h2 class="titleSemantic">Filters</h2><div class="boxheader">
<div class="boxtitle">Filters <a style="float: right;" href="#" onClick="jQuery('#FilterBox').toggle(500); return false;">X</a></div>
</div>
<div class="boxbody">
<form action="/pictures/user/DevilHS/723498/Witchcraft" method="post">
<input type="hidden" value="SHpiT1dzOXpYRU50OVZzRXZOSWp-dzZnTTlmV3U1ck16J9k70kDwVW5YeySDxE7l5lbXi0wmIwy8jihTTFdr3w==" name="YII_CSRF_TOKEN" /><div class='filter_div rating_nudity'>
<label for='rating_nudity'><span style='font-size: 75%'>Show</span> Nudity <span class='rating lvl2' title='Nudity'>N</span></label><select class="ratingListBox" name="rating_nudity" id="rating_nudity">
<option value="0">None</option>
<option value="1">Mild Nudity</option>
<option value="2">Moderate Nudity</option>
<option value="3" selected="selected">Explicit Nudity</option>
</select></div><div class='filter_div rating_violence'>
<label for='rating_violence'><span style='font-size: 75%'>Show</span> Violence <span class='rating lvl2' title='Violence'>V</span></label><select class="ratingListBox" name="rating_violence" id="rating_violence">
<option value="0">None</option>
<option value="1">Comic or Mild Violence</option>
<option value="2">Moderate Violence</option>
<option value="3" selected="selected">Explicit or Graphic Violence</option>
</select></div><div class='filter_div rating_profanity'>
<label for='rating_profanity'><span style='font-size: 75%'>Show</span> Profanity <span class='rating lvl2' title='Profanity'>L</span></label><select class="ratingListBox" name="rating_profanity" id="rating_profanity">
<option value="0">None</option>
<option value="1">Mild Profanity</option>
<option value="2">Moderate Profanity</option>
<option value="3" selected="selected">Proliferous or Severe Profanity</option>
</select></div><div class='filter_div rating_racism'>
<label for='rating_racism'><span style='font-size: 75%'>Show</span> Racism <span class='rating lvl2' title='Racism'>R</span></label><select class="ratingListBox" name="rating_racism" id="rating_racism">
<option value="0">None</option>
<option value="1">Mild Racist themes or content</option>
<option value="2">Racist themes or content</option>
<option value="3" selected="selected">Strong racist themes or content</option>
</select></div><div class='filter_div rating_sex'>
<label for='rating_sex'><span style='font-size: 75%'>Show</span> Sexual content <span class='rating lvl2' title='Sexual content'>Sx</span></label><select class="ratingListBox" name="rating_sex" id="rating_sex">
<option value="0">None</option>
<option value="1">Mild suggestive content</option>
<option value="2">Moderate suggestive or sexual content</option>
<option value="3" selected="selected">Explicit or adult sexual content</option>
</select></div><div class='filter_div rating_spoilers'>
<label for='rating_spoilers'><span style='font-size: 75%'>Show</span> Spoiler Warning <span class='rating lvl2' title='Spoiler Warning'>Sp</span></label><select class="ratingListBox" name="rating_spoilers" id="rating_spoilers">
<option value="0">None</option>
<option value="1">Mild Spoiler Warning</option>
<option value="2">Moderate Spoiler Warning</option>
<option value="3" selected="selected">Major Spoiler Warning</option>
</select></div><div class='filter_div rating_yaoi'>
<label for='rating_yaoi'><span style='font-size: 75%'>Show</span> Yaoi <span class='rating lvl2' title='Shonen-ai (male homosexual) context'>♂♂</span></label><input type="hidden" value="0" name="rating_yaoi" /><input class="ratingCheckbox" checked="checked" type="checkbox" value="1" name="rating_yaoi" id="rating_yaoi" /></div><div class='filter_div rating_yuri'>
<label for='rating_yuri'><span style='font-size: 75%'>Show</span> Yuri <span class='rating lvl2' title='Shoujo-ai (female homosexual) context'>♀♀</span></label><input type="hidden" value="0" name="rating_yuri" /><input class="ratingCheckbox" checked="checked" type="checkbox" value="1" name="rating_yuri" id="rating_yuri" /></div><div class='filter_div rating_teen'>
<label for='rating_teen'><span style='font-size: 75%'>Show</span> Teen <span class='rating lvl2' title='Teen content'>T</span></label><input type="hidden" value="0" name="rating_teen" /><input class="ratingCheckbox" type="checkbox" value="1" name="rating_teen" id="rating_teen" /></div><div class='filter_div rating_guro'>
<label for='rating_guro'><span style='font-size: 75%'>Show</span> Guro <span class='rating lvl2' title='Gore, scat, similar macabre content'>G</span></label><input type="hidden" value="0" name="rating_guro" /><input class="ratingCheckbox" type="checkbox" value="1" name="rating_guro" id="rating_guro" /></div><div class='filter_div rating_furry'>
<label for='rating_furry'><span style='font-size: 75%'>Show</span> Furry <span class='rating lvl2' title='Anthropomorphic/furry content'>F</span></label><input type="hidden" value="0" name="rating_furry" /><input class="ratingCheckbox" type="checkbox" value="1" name="rating_furry" id="rating_furry" /></div><div class='filter_div rating_beast'>
<label for='rating_beast'><span style='font-size: 75%'>Show</span> Beast <span class='rating lvl2' title='Bestiality'>B</span></label><input type="hidden" value="0" name="rating_beast" /><input class="ratingCheckbox" type="checkbox" value="1" name="rating_beast" id="rating_beast" /></div><div class='filter_div rating_male'>
<label for='rating_male'><span style='font-size: 75%'>Show</span> Male <span class='rating lvl2' title='Contains male nudity'></span></label><input type="hidden" value="0" name="rating_male" /><input class="ratingCheckbox" checked="checked" type="checkbox" value="1" name="rating_male" id="rating_male" /></div><div class='filter_div rating_female'>
<label for='rating_female'><span style='font-size: 75%'>Show</span> Female <span class='rating lvl2' title='Contains female nudity'></span></label><input type="hidden" value="0" name="rating_female" /><input class="ratingCheckbox" checked="checked" type="checkbox" value="1" name="rating_female" id="rating_female" /></div><div class='filter_div rating_futa'>
<label for='rating_futa'><span style='font-size: 75%'>Show</span> Futa <span class='rating lvl2' title='Contains Futanari/Dickgirl/Transgender/Hermaphrodite subject'>Tg</span></label><input type="hidden" value="0" name="rating_futa" /><input class="ratingCheckbox" type="checkbox" value="1" name="rating_futa" id="rating_futa" /></div><div class='filter_div rating_other'>
<label for='rating_other'><span style='font-size: 75%'>Show</span> Other <span class='rating lvl2' title='Other offensive content'>!?</span></label><input type="hidden" value="0" name="rating_other" /><input class="ratingCheckbox" type="checkbox" value="1" name="rating_other" id="rating_other" /></div><div class='filter_div rating_scat'>
<label for='rating_scat'><span style='font-size: 75%'>Show</span> Scat <span class='rating lvl2' title='Scat/Coprophilia/Feces'>💩</span></label><input type="hidden" value="0" name="rating_scat" /><input class="ratingCheckbox" type="checkbox" value="1" name="rating_scat" id="rating_scat" /></div><div class='filter_div rating_incest'>
<label for='rating_incest'><span style='font-size: 75%'>Show</span> Incest <span class='rating lvl2' title='Incest'>I</span></label><input type="hidden" value="0" name="rating_incest" /><input class="ratingCheckbox" type="checkbox" value="1" name="rating_incest" id="rating_incest" /></div><div class='filter_div rating_rape'>
<label for='rating_rape'><span style='font-size: 75%'>Show</span> Rape <span class='rating lvl2' title='Non-consensual/Rape/Forced'>Nc</span></label><input type="hidden" value="0" name="rating_rape" /><input class="ratingCheckbox" type="checkbox" value="1" name="rating_rape" id="rating_rape" /></div><br /><div class='filter_div filter_media'><label for="filter_media">Limit Media to</label><select name="filter_media" id="filter_media">
<option value="A" selected="selected">All</option>
<optgroup label="Traditional media">
<optgroup label=".. Drawings">
<option value="1">Charcoal</option>
<option value="2">Colored Pencil / Crayon</option>
<option value="3">Ink or markers</option>
<option value="4">Oil pastels</option>
<option value="5">Graphite pencil</option>
<option value="6">Other drawing</option>
</optgroup>
<optgroup label=".. Paintings">
<option value="11">Airbrush</option>
<option value="12">Acrylics</option>
<option value="13">Oils</option>
<option value="14">Watercolor</option>
<option value="15">Other painting</option>
</optgroup>
<optgroup label=".. Crafts / Physical art">
<option value="21">Plushies</option>
<option value="22">Sculpture</option>
<option value="23">Other crafts</option>
</optgroup>
</optgroup>
<optgroup label="Digital media (CG)">
<option value="31">3D modelling</option>
<option value="33">Digital drawing or painting</option>
<option value="36">MS Paint</option>
<option value="32">Oekaki</option>
<option value="34">Pixel art</option>
<option value="35">Other digital art</option>
</optgroup>
<option value="0">Unspecified</option>
</select></div><div class='filter_div filter_order'><label for="filter_order">Sort By</label><select name="filter_order" id="filter_order">
<option value="date_new" selected="selected">Date Submitted (Newest)</option>
<option value="date_old">Date Submitted (Oldest)</option>
<option value="update_new">Date updated (Newest)</option>
<option value="update_old">Date updated (Oldest)</option>
<option value="a-z">Title A-z</option>
<option value="z-a">Title z-A</option>
<option value="views most">Views (most first)</option>
<option value="rating highest">rating (highest first)</option>
<option value="comments most">Comments (most first)</option>
<option value="faves most">Faves (most first)</option>
<option value="popularity most">Popularity (highest first)</option>
</select></div><div class='filter_div filter_type'><label for="filter_type">Limit Pictures to</label><select name="filter_type" id="filter_type">
<option value="0" selected="selected">All</option>
<option value="1">Regular Pictures</option>
<option value="2">Flash Submissions</option>
</select></div><input type="submit" name="yt1" value="Apply" id="yt1" /><input onClick="jQuery(&#039;#FilterBox&#039;).toggle(500);" name="yt2" type="button" value="Close" /></form></div>
</aside><ul id="yw12">
<li><a href="/site/about">About</a></li>
<li><a href="//forums.hentai-foundry.com/viewforum.php?f=13">FAQ</a></li>
<li><a href="//forums.hentai-foundry.com/">Forums</a></li>
<li><a href="https://discord.gg/t9ukHX2">Discord</a></li>
<li><a href="/category/browse">Browse Categories</a></li>
<li><a href="/users/byletter">Browse Users</a></li>
<li onclick=";" style="cursor: pointer"><a>Browse Submissions</a>
<ul>
<li><a href="/pictures/featured">Featured Submissions</a></li>
<li><a href="/pictures/recent">Recent Submissions</a></li>
<li><a href="/pictures/popular">Popular Submissions</a></li>
<li><a href="/pictures/random">Random Submissions</a></li>
</ul>
</li>
</ul></nav>
<main>
<h1 class="titleSemantic">Witchcraft</h1><center><p>
<!-- Slot number 4 --><a href='http://www.hentaiunited.com/'><img title="" src="//img.hentai-foundry.com/themes/Hentai/images/h-united/hu8.png" alt="" /></a></p></center>
<div class="container" id="page">
<div class="breadcrumbs">
<a href="/">Home</a> &raquo; <a href="/user/DevilHS/profile">DevilHS</a> &raquo; <a href="/pictures/user/DevilHS">Pictures</a> &raquo; <span>Witchcraft</span></div><!-- breadcrumbs -->
<section class="box lvl1" id="picBox">
<h2 class="titleSemantic">Witchcraft</h2><div class="boxheader">
<div class="boxtitle"><span class="imageTitle">Witchcraft</span> <small>by</small> <a href="/user/DevilHS/profile">DevilHS</a> </div>
</div>
<div class="boxbody">
<img width="929" height="1123" class="center" src="//pictures.hentai-foundry.com/d/DevilHS/723498/DevilHS-723498-Witchcraft.png" alt="Witchcraft by DevilHS" /></div>
<div class="boxfooter"> </div>
</section><section class="box lvl1" id="descriptionBox">
<h2 class="titleSemantic">Description</h2><div class="boxheader">
<div class="boxtitle">Description</div>
</div>
<div class="boxbody">
<a href="/user/DevilHS/profile"><img style="float: left" title="DevilHS" src="//avatars.hentai-foundry.com/234691.jpg" alt="DevilHS" /></a><div class='picDescript'>gift for Liru</div></div>
</section><section class="box lvl1" id="yw0">
<h2 class="titleSemantic">General Info</h2><div class="boxheader">
<div class="boxtitle">General Info</div>
</div>
<div class="boxbody">
<div id="favoritesDialog">
</div><table>
<tr><td><b>Ratings</b></td> <td><div class='ratings_box'><span class='rating lvl3' title='Nudity'>N</span><span class='rating lvl3' title='Sexual content'>Sx</span><span class='rating lvl2' title='Contains female nudity'></span><span class='rating lvl2' title='Contains Futanari/Dickgirl/Transgender/Hermaphrodite subject'>Tg</span></div></td> <td><b>Comments</b></td> <td>11</td></tr>
<tr><td><b>Category</b></td> <td><span class="categoryBreadcrumbs">
<a href="/categories/4/Original/pictures">Original</a> &raquo; <a href="/categories/13/Original/Futanari-Dickgirls/pictures">Futanari (Dickgirls)</a></span></td> <td><b>Media</b></td> <td>Digital drawing or painting</td></tr>
<tr><td><b>Date Submitted</b></td> <td><time datetime='2019-07-25T19:29:48-07:00'>July 25, 2019, 7:29:48 PM</time></td> <td><b>Time Taken</b></td> <td></td></tr>
<tr><td><b>Views</b></td> <td>20597</td> <td><b>Reference</b></td> <td></td></tr>
<tr><td><b><a href="#" id="yt0">Favorites...</a></b></td> <td>876</td> <td><b>Keywords</b></td> <td><a rel="tag" href="/search/index?query=witch&amp;search_in=keywords">witch</a>, <a rel="tag" href="/search/index?query=futa&amp;search_in=keywords">futa</a></td></tr>
<!-- <tr><td></td> <td></td> <td><b>Tags (Beta)</b></td> <td></td></tr> -->
<tr><td><b>Vote Score</b></td> <td>649</td> <td><b>License</b></td> <td><span id='license'>Berne Convention</span></td></tr>
</table></div>
</section><section class="box lvl1" id="comments_box">
<h2 class="titleSemantic">Comments</h2><div class="boxheader">
<div class="boxtitle">Comments (11) <div class="boxlinks"><a class="feedLink fa fa-rss" href="/feed/PictureComments/id/723498"></a></div></div>
</div>
<div class="boxbody">
<p>You are not authorized to comment here. Your must be registered and logged in to comment</p><div style="margin-left: 0px;" id="comment_3210484"><section class="box lvl2" id="yw2">
<h3 class="titleSemantic">Kessandra on August 15, 2019, 8:21:56 AM</h3><div class="boxheader">
<div class="boxtitle"><a href="/user/Kessandra/profile">Kessandra</a> <small>on</small> <time datetime="2019-08-15T08:21:56-07:00">August 15, 2019, 8:21:56 AM</time><span class="commentButtons"></span></div>
</div>
<div class="boxbody">
<div class="commentBody"><a class="avatar" href="/user/Kessandra/profile"><img title="Kessandra" src="//avatars.hentai-foundry.com/270836.jpg" alt="Kessandra" /></a>Looks like some beautiful magic is going on. </div></div>
</section></div><div style="margin-left: 0px;" id="comment_3199670"><section class="box lvl2" id="yw3">
<h3 class="titleSemantic">TrueInsanity on July 28, 2019, 4:34:52 AM</h3><div class="boxheader">
<div class="boxtitle"><a href="/user/TrueInsanity/profile">TrueInsanity</a> <small>on</small> <time datetime="2019-07-28T04:34:52-07:00">July 28, 2019, 4:34:52 AM</time><span class="commentButtons"></span></div>
</div>
<div class="boxbody">
<div class="commentBody"><a class="avatar" href="/user/TrueInsanity/profile"><img title="TrueInsanity" src="//avatars.hentai-foundry.com/336662.gif" alt="TrueInsanity" /></a>Oh hell yes</div></div>
</section></div><div style="margin-left: 0px;" id="comment_3199196"><section class="box lvl2" id="yw4">
<h3 class="titleSemantic">Kaze26 on July 27, 2019, 5:23:29 AM</h3><div class="boxheader">
<div class="boxtitle"><a href="/user/Kaze26/profile">Kaze26</a> <small>on</small> <time datetime="2019-07-27T05:23:29-07:00">July 27, 2019, 5:23:29 AM</time><span class="commentButtons"></span></div>
</div>
<div class="boxbody">
<div class="commentBody"><a class="avatar" href="/user/Kaze26/profile"><img title="Kaze26" src="//avatars.hentai-foundry.com/267944.jpg" alt="Kaze26" /></a><strong>Spectacular</strong></div></div>
</section></div><div style="margin-left: 0px;" id="comment_3198544"><section class="box lvl2" id="yw5">
<h3 class="titleSemantic">QuarterLife on July 25, 2019, 6:39:08 PM</h3><div class="boxheader">
<div class="boxtitle"><a href="/user/QuarterLife/profile">QuarterLife</a> <small>on</small> <time datetime="2019-07-25T18:39:08-07:00">July 25, 2019, 6:39:08 PM</time><span class="commentButtons"></span></div>
</div>
<div class="boxbody">
<div class="commentBody"><a class="avatar" href="/user/QuarterLife/profile"><img title="QuarterLife" src="//avatars.hentai-foundry.com/112455.gif" alt="QuarterLife" /></a>I&#039;m curious as to what she&#039;s casting, is it to help her last longer or is it why she has a cock and balls?<br />
<br />
Either way it&#039;s a good picture, good job, nice tight.</div></div>
</section></div><div style="margin-left: 30px;" id="comment_3198632"><section class="box lvl2" id="yw6">
<h3 class="titleSemantic">DevilHS on July 25, 2019, 10:59:26 PM</h3><div class="boxheader">
<div class="boxtitle"><a href="/user/DevilHS/profile">DevilHS</a> <small>on</small> <time datetime="2019-07-25T22:59:26-07:00">July 25, 2019, 10:59:26 PM</time><span class="commentButtons"></span></div>
</div>
<div class="boxbody">
<div class="commentBody"><a class="avatar" href="/user/DevilHS/profile"><img title="DevilHS" src="//avatars.hentai-foundry.com/234691.jpg" alt="DevilHS" /></a>She casted herself a magic dick.</div></div>
</section></div><div style="margin-left: 60px;" id="comment_3198647"><section class="box lvl2" id="yw7">
<h3 class="titleSemantic">QuarterLife on July 26, 2019, 12:00:08 AM</h3><div class="boxheader">
<div class="boxtitle"><a href="/user/QuarterLife/profile">QuarterLife</a> <small>on</small> <time datetime="2019-07-26T00:00:08-07:00">July 26, 2019, 12:00:08 AM</time><span class="commentButtons"></span></div>
</div>
<div class="boxbody">
<div class="commentBody"><a class="avatar" href="/user/QuarterLife/profile"><img title="QuarterLife" src="//avatars.hentai-foundry.com/112455.gif" alt="QuarterLife" /></a>Ah alright, not just a regular dick, but a magic dick, looks like a good dick too. :D</div></div>
</section></div><div style="margin-left: 0px;" id="comment_3198616"><section class="box lvl2" id="yw8">
<h3 class="titleSemantic">XSUBREADERX on July 25, 2019, 9:59:58 PM</h3><div class="boxheader">
<div class="boxtitle"><a href="/user/XSUBREADERX/profile">XSUBREADERX</a> <small>on</small> <time datetime="2019-07-25T21:59:58-07:00">July 25, 2019, 9:59:58 PM</time><span class="commentButtons"></span></div>
</div>
<div class="boxbody">
<div class="commentBody"><a class="avatar" href="/user/XSUBREADERX/profile"><img title="XSUBREADERX" src="//avatars.hentai-foundry.com/376416.jpg" alt="XSUBREADERX" /></a>Very Nice!</div></div>
</section></div><div style="margin-left: 0px;" id="comment_3198548"><section class="box lvl2" id="yw9">
<h3 class="titleSemantic">AceSR on July 25, 2019, 6:41:45 PM</h3><div class="boxheader">
<div class="boxtitle"><a href="/user/AceSR/profile">AceSR</a> <small>on</small> <time datetime="2019-07-25T18:41:45-07:00">July 25, 2019, 6:41:45 PM</time><span class="commentButtons"></span></div>
</div>
<div class="boxbody">
<div class="commentBody"><a class="avatar" href="/user/AceSR/profile"><img title="AceSR" src="//avatars.hentai-foundry.com/360157.gif" alt="AceSR" /></a>Nice gift</div></div>
</section></div><div style="margin-left: 0px;" id="comment_3198498"><section class="box lvl2" id="yw10">
<h3 class="titleSemantic">FloridasSonShines on July 25, 2019, 2:47:00 PM</h3><div class="boxheader">
<div class="boxtitle"><a href="/user/FloridasSonShines/profile">FloridasSonShines</a> <small>on</small> <time datetime="2019-07-25T14:47:00-07:00">July 25, 2019, 2:47:00 PM</time><span class="commentButtons"></span></div>
</div>
<div class="boxbody">
<div class="commentBody"><a class="avatar" href="/user/FloridasSonShines/profile"><img title="FloridasSonShines" src="//avatars.hentai-foundry.com/310539.jpg" alt="FloridasSonShines" /></a>Awesome!</div></div>
</section></div><div style="margin-left: 0px;" id="comment_3198457"><section class="box lvl2" id="yw11">
<h3 class="titleSemantic">Kreegan on July 25, 2019, 12:39:04 PM</h3><div class="boxheader">
<div class="boxtitle"><a href="/user/Kreegan/profile">Kreegan</a> <small>on</small> <time datetime="2019-07-25T12:39:04-07:00">July 25, 2019, 12:39:04 PM</time><span class="commentButtons"></span></div>
</div>
<div class="boxbody">
<div class="commentBody"><a class="avatar" href="/user/Kreegan/profile"><img title="Kreegan" src="//avatars.hentai-foundry.com/227005.jpg" alt="Kreegan" /></a>Great :D<br />
</div></div>
</section></div></div>
<div class="commentsFooter"></div>
</section>
</div><!-- page -->
</main>
<footer id="footer">
<div id="footerText">Site Copyright © 2006-2019 All Rights Reserved<br />Site design by <a href="/user/Sticky/profile">Sticky</a><br />
<br />Art and stories Copyright their artists/writers<br />
Series & Characters Copyright their respective creators/studios<br />
<p>All characters depicted are 18 or older, even if otherwise specified. </p><!-- IPv6-test.com button BEGIN -->
<a href='http://ipv6-test.com/validate.php?url=referer'>
<img src='//img.hentai-foundry.com/themes/default/images/button-ipv6-80x15.png' alt='ipv6 ready' title='ipv6 ready' border='0' />
</a>
<!-- IPv6-test.com button END --><br /><img title="" src="//img.hentai-foundry.com/themes/Hentai/images/icra_sw.gif" alt="" /> <img title="" src="//img.hentai-foundry.com/themes/Hentai/images/88x31_RTA-5042-1996-1400-1577-RTA_c.gif" alt="" /></div>
<br />
<center>
</center>
<br />
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-620339-3', {'cookieDomain': 'www.hentai-foundry.com'});
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');
</script></footer>
<script type="text/javascript" src="//img.hentai-foundry.com/assets/3389c1c0/jui/js/jquery-ui.min.js"></script>
<script type="text/javascript">
/*<![CDATA[*/
document.write('<img src="/site/setSize?size=' + detectResolution() + '" width=0 height=0 id=detectRes>');
jQuery(function($) {
jQuery('body').on('click','#yt0',function(){jQuery.ajax({'success':function(data) { $("#favoritesDialog").html(data).dialog("open"); return false; },'url':'\x2Fpictures\x2Ffans\x3Fpid\x3D723498','cache':false});return false;});
jQuery('#favoritesDialog').dialog({'title':'Fans\x20of\x20\x22Witchcraft\x22','autoOpen':false,'width':'50\x25','height':$(window).height() / 2,'resizable':false});
jQuery('body').on('click','#yt1',function(){jQuery.ajax({'success':function() {location.reload();},'type':'POST','url':'\x2Fsite\x2Ffilters','cache':false,'data':jQuery(this).parents("form").serialize()});return false;});
});
jQuery(window).on('load',function() {
jQuery("#license").qtip({'content':'Default\x20automatic\x20international\x20copyright.\x3Cbr\x20\x2F\x3E\x0A\x3Cbr\x20\x2F\x3E\x0AMore\x20Information\x3A\x20\x3Ca\x20href\x3D\x22http\x3A\x2F\x2Fen.wikipedia.org\x2Fwiki\x2FBerne_Convention_for_the_Protection_of_Literary_and_Artistic_Works\x22\x20rel\x3D\x22nofollow\x22\x3Ehttp\x3A\x2F\x2Fen.wikipedia.org\x2Fwiki\x2FBerne_Convention_for_the_Protection_of_Literary_and_Artistic_Works\x3C\x2Fa\x3E','show':{'delay':50},'position':{'my':'top\x20center','at':'bottom\x20center'},'hide':{'delay':250,'fixed':true},'style':{'classes':'qtip\x2Dlight','tip':'top\x20center'}});
});
/*]]>*/
</script>
</body>
</html>