Compare commits
36 Commits
feature/fi
...
feature/mo
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0522270c1c | ||
![]() |
9bd6b23c05 | ||
![]() |
0e3878a808 | ||
![]() |
4c0b245574 | ||
![]() |
0a0047c4c3 | ||
![]() |
831d1668ef | ||
![]() |
51c8199283 | ||
![]() |
78a1bdfb30 | ||
![]() |
ceff57f9f6 | ||
![]() |
58ae1bc1c1 | ||
![]() |
f7c9e83b12 | ||
![]() |
a1850b666b | ||
![]() |
dddb47f68a | ||
![]() |
1b2b043be2 | ||
![]() |
c535153e1f | ||
![]() |
830de3a5e3 | ||
![]() |
ab46117138 | ||
![]() |
3c2fec21a0 | ||
![]() |
370d1cc01b | ||
![]() |
5517cd5fab | ||
![]() |
3c083a7c60 | ||
![]() |
fa6b8b87af | ||
![]() |
d290bf4107 | ||
![]() |
b274c6bc40 | ||
![]() |
018532f01f | ||
![]() |
e4ef935dd2 | ||
![]() |
fb84a1d416 | ||
![]() |
358580a15e | ||
![]() |
000b89f380 | ||
![]() |
c5cbad4475 | ||
![]() |
f4abb08921 | ||
![]() |
38eb0348f9 | ||
![]() |
4f5595dae0 | ||
![]() |
733e97bc58 | ||
![]() |
c4768ded38 | ||
![]() |
598d27f6b8 |
@@ -1,9 +1,9 @@
|
||||
version: 2
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
executors:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/php:7.1-node-browsers
|
||||
- image: circleci/php:7.3-node-browsers
|
||||
environment:
|
||||
APP_DEBUG: true
|
||||
APP_ENV: testing
|
||||
@@ -17,38 +17,75 @@ jobs:
|
||||
POSTGRES_DB: tissue
|
||||
POSTGRES_USER: tissue
|
||||
POSTGRES_PASSWORD: tissue
|
||||
|
||||
commands:
|
||||
initialize:
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- run: sudo apt update
|
||||
- run: sudo apt install -y libpq-dev
|
||||
- run: sudo docker-php-ext-install zip
|
||||
- run: sudo docker-php-ext-install pdo_pgsql
|
||||
|
||||
restore_composer:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "composer.json" }}
|
||||
- v1-dependencies-
|
||||
- run: composer install -n --prefer-dist
|
||||
save_composer:
|
||||
steps:
|
||||
- save_cache:
|
||||
key: v1-dependencies-{{ checksum "composer.json" }}
|
||||
paths:
|
||||
- ./vendor
|
||||
|
||||
restore_npm:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "package.json" }}
|
||||
- v1-dependencies-
|
||||
- run: yarn install
|
||||
save_npm:
|
||||
steps:
|
||||
- save_cache:
|
||||
key: v1-dependencies-{{ checksum "package.json" }}
|
||||
paths:
|
||||
- ./node_modules
|
||||
- ~/.yarn
|
||||
|
||||
- run: php artisan migrate
|
||||
jobs:
|
||||
build:
|
||||
executor: build
|
||||
steps:
|
||||
- initialize
|
||||
|
||||
- restore_composer
|
||||
- run: composer install -n --prefer-dist
|
||||
- save_composer
|
||||
|
||||
- restore_npm
|
||||
- run: yarn install
|
||||
- save_npm
|
||||
|
||||
- run: yarn run prod
|
||||
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths:
|
||||
- public
|
||||
|
||||
test:
|
||||
executor: build
|
||||
steps:
|
||||
- initialize
|
||||
|
||||
- restore_composer
|
||||
- restore_npm
|
||||
|
||||
- attach_workspace:
|
||||
at: .
|
||||
|
||||
- run: php artisan migrate
|
||||
|
||||
# Run linter
|
||||
- run:
|
||||
command: |
|
||||
@@ -79,3 +116,51 @@ jobs:
|
||||
- run:
|
||||
command: bash <(curl -s https://codecov.io/bash) -f /tmp/phpunit/coverage.xml
|
||||
when: always
|
||||
|
||||
test_resolver:
|
||||
executor: build
|
||||
environment:
|
||||
TEST_USE_HTTP_MOCK: false
|
||||
steps:
|
||||
- initialize
|
||||
|
||||
- restore_composer
|
||||
|
||||
- attach_workspace:
|
||||
at: .
|
||||
|
||||
- run: php artisan migrate
|
||||
|
||||
# Run unit test
|
||||
- run:
|
||||
command: |
|
||||
mkdir -p /tmp/phpunit
|
||||
./vendor/bin/phpunit --testsuite MetadataResolver --log-junit /tmp/phpunit/phpunit.xml --coverage-clover=/tmp/phpunit/coverage.xml
|
||||
when: always
|
||||
- store_test_results:
|
||||
path: /tmp/phpunit
|
||||
- store_artifacts:
|
||||
path: /tmp/phpunit/coverage.xml
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
test:
|
||||
jobs:
|
||||
- build
|
||||
- test:
|
||||
requires:
|
||||
- build
|
||||
scheduled_resolver_test:
|
||||
triggers:
|
||||
- schedule:
|
||||
cron: "4 0 * * 1"
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
jobs:
|
||||
- build
|
||||
- test_resolver:
|
||||
requires:
|
||||
- build
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
FROM node:10-jessie as node
|
||||
|
||||
FROM php:7.1-apache
|
||||
FROM php:7.3-apache
|
||||
|
||||
ENV APACHE_DOCUMENT_ROOT /var/www/html/public
|
||||
|
||||
@@ -10,6 +10,7 @@ RUN apt-get update \
|
||||
&& pecl install xdebug \
|
||||
&& curl -sS https://getcomposer.org/installer | php \
|
||||
&& mv composer.phar /usr/local/bin/composer \
|
||||
&& composer global require hirak/prestissimo \
|
||||
&& sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \
|
||||
&& sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf \
|
||||
&& a2enmod rewrite
|
||||
|
@@ -36,7 +36,6 @@ docker-compose up -d
|
||||
4. Composer と yarn を使い必要なライブラリをインストールします。
|
||||
|
||||
```
|
||||
docker-compose exec web composer global require hirak/prestissimo
|
||||
docker-compose exec web composer install
|
||||
docker-compose exec web yarn install
|
||||
```
|
||||
|
@@ -109,13 +109,6 @@ SQL
|
||||
}
|
||||
}
|
||||
|
||||
// 月間グラフ用の配列初期化
|
||||
$month = Carbon::now()->firstOfMonth()->subMonth(11); // 直近12ヶ月
|
||||
for ($i = 0; $i < 12; $i++) {
|
||||
$monthlySum[$month->format('Y/m')] = 0;
|
||||
$month->addMonth();
|
||||
}
|
||||
|
||||
foreach ($groupByDay as $data) {
|
||||
$date = Carbon::createFromFormat('Y/m/d', $data->date);
|
||||
$yearAndMonth = $date->format('Y/m');
|
||||
@@ -123,9 +116,7 @@ SQL
|
||||
$dailySum[$date->timestamp] = $data->count;
|
||||
$yearlySum[$date->year] += $data->count;
|
||||
$dowSum[$date->dayOfWeek] += $data->count;
|
||||
if (isset($monthlySum[$yearAndMonth])) {
|
||||
$monthlySum[$yearAndMonth] += $data->count;
|
||||
}
|
||||
$monthlySum[$yearAndMonth] = ($monthlySum[$yearAndMonth] ?? 0) + $data->count;
|
||||
}
|
||||
|
||||
foreach ($groupByHour as $data) {
|
||||
@@ -136,8 +127,7 @@ SQL
|
||||
$graphData = [
|
||||
'dailySum' => $dailySum,
|
||||
'dowSum' => $dowSum,
|
||||
'monthlyKey' => array_keys($monthlySum),
|
||||
'monthlySum' => array_values($monthlySum),
|
||||
'monthlySum' => $monthlySum,
|
||||
'yearlyKey' => array_keys($yearlySum),
|
||||
'yearlySum' => array_values($yearlySum),
|
||||
'hourlyKey' => array_keys($hourlySum),
|
||||
|
@@ -28,6 +28,7 @@ class MetadataResolver implements Resolver
|
||||
'~www\.plurk\.com\/p\/.*~' => PlurkResolver::class,
|
||||
'~(adult\.)?contents\.fc2\.com\/article_search\.php\?id=\d+~' => FC2ContentsResolver::class,
|
||||
'~store\.steampowered\.com/app/\d+~' => SteamResolver::class,
|
||||
'~www\.xtube\.com/video-watch/.*-\d+$~'=> XtubeResolver::class,
|
||||
];
|
||||
|
||||
public $mimeTypes = [
|
||||
|
@@ -24,11 +24,19 @@ class ToranoanaResolver implements Resolver
|
||||
|
||||
public function resolve(string $url): Metadata
|
||||
{
|
||||
$cookieJar = CookieJar::fromArray(['adflg' => '0'], 'ec.toranoana.jp');
|
||||
|
||||
$res = $this->client->get($url, ['cookies' => $cookieJar]);
|
||||
$res = $this->client->get($url);
|
||||
if ($res->getStatusCode() === 200) {
|
||||
return $this->ogpResolver->parse($res->getBody());
|
||||
$metadata = $this->ogpResolver->parse($res->getBody());
|
||||
|
||||
$dom = new \DOMDocument();
|
||||
@$dom->loadHTML(mb_convert_encoding($res->getBody(), 'HTML-ENTITIES', 'UTF-8'));
|
||||
$xpath = new \DOMXPath($dom);
|
||||
$imgNode = $xpath->query('//*[@id="preview"]//img')->item(0);
|
||||
if ($imgNode !== null) {
|
||||
$metadata->image = $imgNode->getAttribute('src');
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
} else {
|
||||
throw new \RuntimeException("{$res->getStatusCode()}: $url");
|
||||
}
|
||||
|
41
app/MetadataResolver/XtubeResolver.php
Normal file
41
app/MetadataResolver/XtubeResolver.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\MetadataResolver;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
class XtubeResolver implements Resolver
|
||||
{
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
private $client;
|
||||
|
||||
public function __construct(Client $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
public function resolve(string $url): Metadata
|
||||
{
|
||||
if (preg_match('~www\.xtube\.com/video-watch/.*-(\d+)$~', $url, $matches) !== 1) {
|
||||
throw new \RuntimeException("Unmatched URL Pattern: $url");
|
||||
}
|
||||
$videoid = $matches[1];
|
||||
|
||||
$res = $this->client->get('https://www.xtube.com/webmaster/api/getvideobyid?video_id=' . $videoid);
|
||||
if ($res->getStatusCode() === 200) {
|
||||
$data = json_decode($res->getBody()->getContents(), true);
|
||||
$metadata = new Metadata();
|
||||
|
||||
$metadata->title = $data['title'] ?? '';
|
||||
$metadata->description = strip_tags(str_replace('\n', PHP_EOL, html_entity_decode($data['description'] ?? '')));
|
||||
$metadata->image = str_replace('eSuQ8f', 'eSK08f', $data['thumb'] ?? ''); // 300x169 to 300x210
|
||||
$metadata->tags = array_values(array_unique($data['tags']));
|
||||
|
||||
return $metadata;
|
||||
} else {
|
||||
throw new \RuntimeException("{$res->getStatusCode()}: $url");
|
||||
}
|
||||
}
|
||||
}
|
@@ -13,7 +13,9 @@
|
||||
"laravel/framework": "5.5.*",
|
||||
"laravel/tinker": "~1.0",
|
||||
"misd/linkify": "^1.1",
|
||||
"staudenmeir/eloquent-eager-limit": "^1.0"
|
||||
"staudenmeir/eloquent-eager-limit": "^1.0",
|
||||
"symfony/css-selector": "^4.3",
|
||||
"symfony/dom-crawler": "^4.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.1",
|
||||
|
84
composer.lock
generated
84
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "665f6f5eb180a1295fb60303d2ea5051",
|
||||
"content-hash": "28abd730d4572663d10ae815393c73cd",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anhskohbo/no-captcha",
|
||||
@@ -2113,16 +2113,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/css-selector",
|
||||
"version": "v4.2.1",
|
||||
"version": "v4.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/css-selector.git",
|
||||
"reference": "aa9fa526ba1b2ec087ffdfb32753803d999fcfcd"
|
||||
"reference": "105c98bb0c5d8635bea056135304bd8edcc42b4d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/aa9fa526ba1b2ec087ffdfb32753803d999fcfcd",
|
||||
"reference": "aa9fa526ba1b2ec087ffdfb32753803d999fcfcd",
|
||||
"url": "https://api.github.com/repos/symfony/css-selector/zipball/105c98bb0c5d8635bea056135304bd8edcc42b4d",
|
||||
"reference": "105c98bb0c5d8635bea056135304bd8edcc42b4d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2131,7 +2131,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.2-dev"
|
||||
"dev-master": "4.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2147,14 +2147,14 @@
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jean-François Simon",
|
||||
"email": "jeanfrancois.simon@sensiolabs.com"
|
||||
},
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Jean-François Simon",
|
||||
"email": "jeanfrancois.simon@sensiolabs.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
@@ -2162,7 +2162,7 @@
|
||||
],
|
||||
"description": "Symfony CssSelector Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-11-11T19:52:12+00:00"
|
||||
"time": "2019-01-16T21:53:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/debug",
|
||||
@@ -2220,6 +2220,67 @@
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-11-27T12:43:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dom-crawler",
|
||||
"version": "v4.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dom-crawler.git",
|
||||
"reference": "291397232a2eefb3347eaab9170409981eaad0e2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/291397232a2eefb3347eaab9170409981eaad0e2",
|
||||
"reference": "291397232a2eefb3347eaab9170409981eaad0e2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"symfony/polyfill-ctype": "~1.8",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"masterminds/html5": "<2.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"masterminds/html5": "^2.6",
|
||||
"symfony/css-selector": "~3.4|~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/css-selector": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\DomCrawler\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony DomCrawler Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2019-06-13T11:03:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v4.2.1",
|
||||
@@ -4888,6 +4949,7 @@
|
||||
"mock",
|
||||
"xunit"
|
||||
],
|
||||
"abandoned": true,
|
||||
"time": "2018-08-09T05:50:03+00:00"
|
||||
},
|
||||
{
|
||||
|
@@ -16,6 +16,7 @@
|
||||
"cal-heatmap": "^3.3.10",
|
||||
"chart.js": "^2.7.1",
|
||||
"cross-env": "^5.2.0",
|
||||
"date-fns": "^1.30.1",
|
||||
"husky": "^1.3.1",
|
||||
"jquery": "^3.2.1",
|
||||
"js-cookie": "^2.2.0",
|
||||
|
@@ -16,6 +16,10 @@
|
||||
<testsuite name="Unit">
|
||||
<directory suffix="Test.php">./tests/Unit</directory>
|
||||
</testsuite>
|
||||
|
||||
<testsuite name="MetadataResolver">
|
||||
<directory suffix="Test.php">./tests/Unit/MetadataResolver</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
|
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
<div v-else-if="state === MetadataLoadState.Success" class="row no-gutters">
|
||||
<div v-if="hasImage" class="col-4 justify-content-center align-items-center">
|
||||
<img :src="metadata.image" alt="Thumbnail" class="card-img-top-to-left bg-secondary">
|
||||
<img :src="metadata.image" alt="Thumbnail" class="w-100 bg-secondary">
|
||||
</div>
|
||||
<div :class="descClasses">
|
||||
<div class="card-body">
|
||||
@@ -20,8 +20,8 @@
|
||||
<p class="card-text mb-2" style="font-size: small;">タグ候補<br><span class="text-secondary">(クリックするとタグ入力欄にコピーできます)</span></p>
|
||||
<ul class="list-inline d-inline">
|
||||
<li v-for="tag in suggestions"
|
||||
class="list-inline-item badge badge-primary metadata-tag-item"
|
||||
@click="addTag(tag)"><span class="oi oi-tag"></span> {{ tag }}</li>
|
||||
:class="tagClasses(tag)"
|
||||
@click="addTag(tag.name)"><span class="oi oi-tag"></span> {{ tag.name }}</li>
|
||||
</ul>
|
||||
</template>
|
||||
</div>
|
||||
@@ -54,6 +54,11 @@
|
||||
}[],
|
||||
};
|
||||
|
||||
type Suggestion = {
|
||||
name: string,
|
||||
used: boolean,
|
||||
}
|
||||
|
||||
@Component
|
||||
export default class MetadataPreview extends Vue {
|
||||
@Prop() readonly state!: MetadataLoadState;
|
||||
@@ -62,16 +67,38 @@
|
||||
// for use in v-if
|
||||
private readonly MetadataLoadState = MetadataLoadState;
|
||||
|
||||
tags: string[] = [];
|
||||
|
||||
created() {
|
||||
bus.$on("change-tag", (tags: string[]) => this.tags = tags);
|
||||
bus.$emit("resend-tag");
|
||||
}
|
||||
|
||||
addTag(tag: string) {
|
||||
bus.$emit("add-tag", tag);
|
||||
}
|
||||
|
||||
get suggestions() {
|
||||
tagClasses(s: Suggestion) {
|
||||
return {
|
||||
"list-inline-item": true,
|
||||
"badge": true,
|
||||
"badge-primary": !s.used,
|
||||
"badge-secondary": s.used,
|
||||
"metadata-tag-item": true,
|
||||
};
|
||||
}
|
||||
|
||||
get suggestions(): Suggestion[] {
|
||||
if (this.metadata === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.metadata.tags.map(t => t.name);
|
||||
return this.metadata.tags.map(t => {
|
||||
return {
|
||||
name: t.name,
|
||||
used: this.tags.indexOf(t.name) !== -1
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
get hasImage() {
|
||||
@@ -90,10 +117,7 @@
|
||||
<style lang="scss" scoped>
|
||||
.link-card-mini {
|
||||
$height: 150px;
|
||||
|
||||
.row > div {
|
||||
overflow: hidden;
|
||||
}
|
||||
overflow: hidden;
|
||||
|
||||
.row > div:first-child {
|
||||
display: flex;
|
||||
|
@@ -16,7 +16,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {Vue, Component, Prop} from "vue-property-decorator";
|
||||
import {Vue, Component, Prop, Watch} from "vue-property-decorator";
|
||||
import {bus} from "../checkin";
|
||||
|
||||
@Component
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
created() {
|
||||
bus.$on("add-tag", (tag: string) => this.tags.indexOf(tag) === -1 && this.tags.push(tag));
|
||||
bus.$on("resend-tag", () => bus.$emit("change-tag", this.tags));
|
||||
}
|
||||
|
||||
onKeyDown(event: KeyboardEvent) {
|
||||
@@ -56,6 +57,11 @@
|
||||
this.tags.splice(index, 1);
|
||||
}
|
||||
|
||||
@Watch("tags")
|
||||
onTagsChanged() {
|
||||
bus.$emit("change-tag", this.tags);
|
||||
}
|
||||
|
||||
get containerClass(): object {
|
||||
return {
|
||||
"form-control": true,
|
||||
|
57
resources/assets/js/user/stats.js
vendored
57
resources/assets/js/user/stats.js
vendored
@@ -1,9 +1,12 @@
|
||||
import CalHeatMap from 'cal-heatmap';
|
||||
import Chart from 'chart.js';
|
||||
import {addMonths, format, startOfMonth, subMonths} from 'date-fns';
|
||||
|
||||
const graphData = JSON.parse(document.getElementById('graph-data').textContent);
|
||||
|
||||
function createLineGraph(id, labels, data) {
|
||||
const context = document.getElementById(id).getContext('2d');
|
||||
new Chart(context, {
|
||||
return new Chart(context, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
@@ -62,7 +65,22 @@ function createBarGraph(id, labels, data) {
|
||||
});
|
||||
}
|
||||
|
||||
const graphData = JSON.parse(document.getElementById('graph-data').textContent);
|
||||
/**
|
||||
* @param {Date} from
|
||||
*/
|
||||
function createMonthlyGraphData(from) {
|
||||
const keys = [];
|
||||
const values = [];
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const current = addMonths(from, i);
|
||||
const yearAndMonth = format(current, 'YYYY/MM');
|
||||
keys.push(yearAndMonth);
|
||||
values.push(graphData.monthlySum[yearAndMonth] || 0);
|
||||
}
|
||||
|
||||
return {keys, values};
|
||||
}
|
||||
|
||||
new CalHeatMap().init({
|
||||
itemSelector: '#cal-heatmap',
|
||||
@@ -76,7 +94,40 @@ new CalHeatMap().init({
|
||||
legend: [1, 2, 3, 4]
|
||||
});
|
||||
|
||||
createLineGraph('monthly-graph', graphData.monthlyKey, graphData.monthlySum);
|
||||
// 直近1年の月間グラフのデータを準備
|
||||
const monthlyTermFrom = subMonths(startOfMonth(new Date()), 11);
|
||||
const {keys: monthlyKey, values: monthlySum} = createMonthlyGraphData(monthlyTermFrom);
|
||||
|
||||
const monthlyGraph = createLineGraph('monthly-graph', monthlyKey, monthlySum);
|
||||
createLineGraph('yearly-graph', graphData.yearlyKey, graphData.yearlySum);
|
||||
createBarGraph('hourly-graph', graphData.hourlyKey, graphData.hourlySum);
|
||||
createBarGraph('dow-graph', ['日', '月', '火', '水', '木', '金', '土'], graphData.dowSum);
|
||||
|
||||
// 月間グラフの期間セレクターを準備
|
||||
const monthlyTermSelector = document.getElementById('monthly-term');
|
||||
for (let year = monthlyTermFrom.getFullYear(); year <= new Date().getFullYear(); year++) {
|
||||
const opt = document.createElement('option');
|
||||
opt.setAttribute('value', year);
|
||||
opt.textContent = `${year}年`;
|
||||
monthlyTermSelector.insertBefore(opt, monthlyTermSelector.firstChild);
|
||||
}
|
||||
if (monthlyTermSelector.children.length) {
|
||||
monthlyTermSelector.selectedIndex = 0;
|
||||
}
|
||||
|
||||
monthlyTermSelector.addEventListener('change', function (e) {
|
||||
let monthlyTermFrom;
|
||||
if (e.target.selectedIndex === 0) {
|
||||
// 今年のデータを表示する時は、直近12ヶ月を表示
|
||||
monthlyTermFrom = subMonths(startOfMonth(new Date()), 11);
|
||||
} else {
|
||||
// 過去のデータを表示する時は、選択年の1〜12月を表示
|
||||
monthlyTermFrom = new Date(e.target.value, 0, 1);
|
||||
}
|
||||
|
||||
const {keys, values} = createMonthlyGraphData(monthlyTermFrom);
|
||||
|
||||
monthlyGraph.data.labels = keys;
|
||||
monthlyGraph.data.datasets[0].data = values;
|
||||
monthlyGraph.update();
|
||||
});
|
||||
|
19
resources/assets/sass/_bootstrap-custom.scss
vendored
19
resources/assets/sass/_bootstrap-custom.scss
vendored
@@ -1,19 +0,0 @@
|
||||
.card-img-left {
|
||||
width: 100%;
|
||||
@include border-left-radius($card-inner-border-radius);
|
||||
}
|
||||
|
||||
.card-img-right {
|
||||
width: 100%;
|
||||
@include border-right-radius($card-inner-border-radius);
|
||||
}
|
||||
|
||||
.card-img-top-to-left {
|
||||
width: 100%;
|
||||
@include media-breakpoint-down(md) {
|
||||
@include border-top-radius($card-inner-border-radius);
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
@include border-left-radius($card-inner-border-radius);
|
||||
}
|
||||
}
|
1
resources/assets/sass/app.scss
vendored
1
resources/assets/sass/app.scss
vendored
@@ -3,7 +3,6 @@ $primary: #e53fb1;
|
||||
|
||||
// Bootstrap
|
||||
@import "~bootstrap/scss/bootstrap";
|
||||
@import "bootstrap-custom";
|
||||
|
||||
// Open Iconic
|
||||
@import "~open-iconic/font/css/open-iconic-bootstrap";
|
||||
|
@@ -1,4 +1,6 @@
|
||||
.link-card {
|
||||
overflow: hidden;
|
||||
|
||||
.row > div {
|
||||
max-height: 400px;
|
||||
overflow: hidden;
|
||||
|
1
resources/assets/sass/tissue.css
vendored
1
resources/assets/sass/tissue.css
vendored
@@ -77,3 +77,4 @@
|
||||
#navbarAccountDropdownSp {
|
||||
max-width: calc(100vw - 5em);
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<a class="text-dark card-link" href="{{ $link }}" target="_blank" rel="noopener">
|
||||
<div class="row no-gutters">
|
||||
<div class="col-12 col-md-6 justify-content-center align-items-center">
|
||||
<img src="" alt="Thumbnail" class="card-img-top-to-left bg-secondary">
|
||||
<img src="" alt="Thumbnail" class="w-100 bg-secondary">
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="card-body">
|
||||
|
@@ -15,7 +15,14 @@
|
||||
<h5 class="my-4">Shikontribution graph</h5>
|
||||
<div id="cal-heatmap" class="tis-contribution-graph"></div>
|
||||
<hr class="my-4">
|
||||
<h5 class="my-4">月間チェックイン回数</h5>
|
||||
<div class="row my-4">
|
||||
<div class="col-12 col-lg-6 d-flex align-items-center">
|
||||
<h5 class="my-0">月間チェックイン回数</h5>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mt-2 mt-lg-0">
|
||||
<select id="monthly-term" class="form-control"></select>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="monthly-graph" class="w-100"></canvas>
|
||||
<hr class="my-4">
|
||||
<h5 class="my-4">年間チェックイン回数</h5>
|
||||
|
@@ -22,12 +22,12 @@ trait CreateMockedResolver
|
||||
|
||||
/**
|
||||
* @param string $resolverClass
|
||||
* @param string $responseText
|
||||
* @param string|array $response
|
||||
* @param array $headers
|
||||
* @param int $status
|
||||
* @return Resolver
|
||||
*/
|
||||
protected function createResolver(string $resolverClass, string $responseText, array $headers = [], int $status = 200)
|
||||
protected function createResolver(string $resolverClass, $response, array $headers = [], int $status = 200)
|
||||
{
|
||||
if (!$this->shouldUseMock()) {
|
||||
$this->resolver = app()->make($resolverClass);
|
||||
@@ -39,8 +39,26 @@ trait CreateMockedResolver
|
||||
'content-type' => 'text/html',
|
||||
];
|
||||
|
||||
$mockResponse = new Response($status, $headers, $responseText);
|
||||
$this->handler = new MockHandler([$mockResponse]);
|
||||
if (is_array($response)) {
|
||||
$responses = $response;
|
||||
$mockResponses = [];
|
||||
foreach ($responses as $response) {
|
||||
if (is_array($response)) {
|
||||
$response += [
|
||||
1 => $headers,
|
||||
2 => $status
|
||||
];
|
||||
array_push($mockResponses, new Response($response[2], $response[1], $response[0]));
|
||||
} else {
|
||||
array_push($mockResponses, new Response($status, $headers, $response));
|
||||
}
|
||||
}
|
||||
$this->handler = new MockHandler($mockResponses);
|
||||
} else {
|
||||
$mockResponse = new Response($status, $headers, $response);
|
||||
$this->handler = new MockHandler([$mockResponse]);
|
||||
}
|
||||
|
||||
$client = new Client(['handler' => $this->handler]);
|
||||
$this->resolver = app()->make($resolverClass, ['client' => $client]);
|
||||
|
||||
|
@@ -40,13 +40,13 @@ class PixivResolverTest extends TestCase
|
||||
|
||||
$this->createResolver(PixivResolver::class, $responseText);
|
||||
|
||||
$metadata = $this->resolver->resolve('https://www.pixiv.net/member_illust.php?mode=medium&illust_id=74939802');
|
||||
$this->assertEquals('T-20S', $metadata->title);
|
||||
$this->assertEquals('投稿者: amssc' . PHP_EOL . 'JUST FOR FUN' . PHP_EOL . '现在可以做到游戏内立绘修改拉!立绘动态皮肤都可以支持,想要资助获得新技术请站内信联系我。', $metadata->description);
|
||||
$this->assertEquals('https://i.pixiv.cat/img-master/img/2019/05/28/01/16/24/74939802_p0_master1200.jpg', $metadata->image);
|
||||
$this->assertEquals(['巨乳', '母乳', 'lastorigin', 'Last_Origin', 'T-20S', 'おっぱい', '라스트오리진', '노움'], $metadata->tags);
|
||||
$metadata = $this->resolver->resolve('https://www.pixiv.net/member_illust.php?mode=medium&illust_id=75899985');
|
||||
$this->assertEquals('コミッション絵33', $metadata->title);
|
||||
$this->assertEquals('投稿者: ナゼ(NAZE)' . PHP_EOL . 'Leak' . PHP_EOL . PHP_EOL . 'Character:アリッサさん(依頼主のオリキャラ)', $metadata->description);
|
||||
$this->assertEquals('https://i.pixiv.cat/img-master/img/2019/07/25/13/02/59/75899985_p0_master1200.jpg', $metadata->image);
|
||||
$this->assertEquals(['巨乳輪', '超乳', '巨乳首', '母乳'], $metadata->tags);
|
||||
if ($this->shouldUseMock()) {
|
||||
$this->assertSame('https://www.pixiv.net/ajax/illust/74939802', (string) $this->handler->getLastRequest()->getUri());
|
||||
$this->assertSame('https://www.pixiv.net/ajax/illust/75899985', (string) $this->handler->getLastRequest()->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
|
140
tests/Unit/MetadataResolver/ToranoanaResolverTest.php
Normal file
140
tests/Unit/MetadataResolver/ToranoanaResolverTest.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\MetadataResolver;
|
||||
|
||||
use App\MetadataResolver\ToranoanaResolver;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ToranoanaResolverTest extends TestCase
|
||||
{
|
||||
use CreateMockedResolver;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!$this->shouldUseMock()) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
public function testTora()
|
||||
{
|
||||
$responseText = file_get_contents(__DIR__ . '/../../fixture/Toranoana/testTora.html');
|
||||
|
||||
$this->createResolver(ToranoanaResolver::class, $responseText);
|
||||
|
||||
$metadata = $this->resolver->resolve('https://ec.toranoana.shop/tora/ec/item/040030720152');
|
||||
$this->assertEquals('新・古明地喫茶~そしてまた扉は開く~', $metadata->title);
|
||||
$this->assertEquals('サークル【ツキギのとこ】(槻木こうすけ)発行の「新・古明地喫茶~そしてまた扉は開く~」を買うなら、とらのあな全年齢向け通信販売!', $metadata->description);
|
||||
$this->assertRegExp('~ecdnimg\.toranoana\.jp/ec/img/.*\.jpg~', $metadata->image);
|
||||
if ($this->shouldUseMock()) {
|
||||
$this->assertSame('https://ec.toranoana.shop/tora/ec/item/040030720152', (string) $this->handler->getLastRequest()->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
public function testToraR()
|
||||
{
|
||||
$responseText = file_get_contents(__DIR__ . '/../../fixture/Toranoana/testToraR.html');
|
||||
|
||||
$this->createResolver(ToranoanaResolver::class, $responseText);
|
||||
|
||||
$metadata = $this->resolver->resolve('https://ec.toranoana.jp/tora_r/ec/item/040030720174');
|
||||
$this->assertEquals('お姉ちゃんが妹のぱんつでひとりえっちしてました。', $metadata->title);
|
||||
$this->assertEquals('サークル【没後】(RYO)発行の「お姉ちゃんが妹のぱんつでひとりえっちしてました。」を買うなら、とらのあな成年向け通信販売!', $metadata->description);
|
||||
$this->assertRegExp('~ecdnimg\.toranoana\.jp/ec/img/.*\.jpg~', $metadata->image);
|
||||
if ($this->shouldUseMock()) {
|
||||
$this->assertSame('https://ec.toranoana.jp/tora_r/ec/item/040030720174', (string) $this->handler->getLastRequest()->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
public function testToraD()
|
||||
{
|
||||
$responseText = file_get_contents(__DIR__ . '/../../fixture/Toranoana/testToraD.html');
|
||||
|
||||
$this->createResolver(ToranoanaResolver::class, $responseText);
|
||||
|
||||
$metadata = $this->resolver->resolve('https://ec.toranoana.shop/tora_d/digi/item/042000013358');
|
||||
$this->assertEquals('虎の穴ラボの薄い本。vol 1.5', $metadata->title);
|
||||
$this->assertEquals('サークル【虎の穴ラボ】(虎の穴ラボエンジニアチーム)発行の「虎の穴ラボの薄い本。vol 1.5」を買うなら、とらのあな全年齢向け電子書籍!', $metadata->description);
|
||||
$this->assertRegExp('~ecdnimg\.toranoana\.jp/ec/img/.*\.jpg~', $metadata->image);
|
||||
if ($this->shouldUseMock()) {
|
||||
$this->assertSame('https://ec.toranoana.shop/tora_d/digi/item/042000013358', (string) $this->handler->getLastRequest()->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
public function testToraRD()
|
||||
{
|
||||
$responseText = file_get_contents(__DIR__ . '/../../fixture/Toranoana/testToraRD.html');
|
||||
|
||||
$this->createResolver(ToranoanaResolver::class, $responseText);
|
||||
|
||||
$metadata = $this->resolver->resolve('https://ec.toranoana.jp/tora_rd/digi/item/042000013181');
|
||||
$this->assertEquals('放課後のお花摘み', $metadata->title);
|
||||
$this->assertEquals('サークル【給食泥棒】(村雲)発行の「放課後のお花摘み」を買うなら、とらのあな成年向け電子書籍!', $metadata->description);
|
||||
$this->assertRegExp('~ecdnimg\.toranoana\.jp/ec/img/.*\.jpg~', $metadata->image);
|
||||
if ($this->shouldUseMock()) {
|
||||
$this->assertSame('https://ec.toranoana.jp/tora_rd/digi/item/042000013181', (string) $this->handler->getLastRequest()->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
public function testJoshi()
|
||||
{
|
||||
$responseText = file_get_contents(__DIR__ . '/../../fixture/Toranoana/testJoshi.html');
|
||||
|
||||
$this->createResolver(ToranoanaResolver::class, $responseText);
|
||||
|
||||
$metadata = $this->resolver->resolve('https://ec.toranoana.shop/joshi/ec/item/040030702729');
|
||||
$this->assertEquals('円卓のクソ漫画', $metadata->title);
|
||||
$this->assertEquals('サークル【地獄のすなぎもカーニバル】(槌田)発行の「円卓のクソ漫画」を買うなら、とらのあなJOSHIBU全年齢向け通信販売!', $metadata->description);
|
||||
$this->assertRegExp('~ecdnimg\.toranoana\.jp/ec/img/.*\.jpg~', $metadata->image);
|
||||
if ($this->shouldUseMock()) {
|
||||
$this->assertSame('https://ec.toranoana.shop/joshi/ec/item/040030702729', (string) $this->handler->getLastRequest()->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
public function testJoshiR()
|
||||
{
|
||||
$responseText = file_get_contents(__DIR__ . '/../../fixture/Toranoana/testJoshiR.html');
|
||||
|
||||
$this->createResolver(ToranoanaResolver::class, $responseText);
|
||||
|
||||
$metadata = $this->resolver->resolve('https://ec.toranoana.jp/joshi_r/ec/item/040030730126');
|
||||
$this->assertEquals('リバースナイトリバース', $metadata->title);
|
||||
$this->assertEquals('サークル【雨傘サイクル】(チャリリズム)発行の「リバースナイトリバース」を買うなら、とらのあなJOSHIBU成年向け通信販売!', $metadata->description);
|
||||
$this->assertRegExp('~ecdnimg\.toranoana\.jp/ec/img/.*\.jpg~', $metadata->image);
|
||||
if ($this->shouldUseMock()) {
|
||||
$this->assertSame('https://ec.toranoana.jp/joshi_r/ec/item/040030730126', (string) $this->handler->getLastRequest()->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
public function testJoshiD()
|
||||
{
|
||||
$responseText = file_get_contents(__DIR__ . '/../../fixture/Toranoana/testJoshiD.html');
|
||||
|
||||
$this->createResolver(ToranoanaResolver::class, $responseText);
|
||||
|
||||
$metadata = $this->resolver->resolve('https://ec.toranoana.shop/joshi_d/digi/item/042000012192');
|
||||
$this->assertEquals('超幸運ガール審神者GOLDEN', $metadata->title);
|
||||
$this->assertEquals('サークル【Day Of The Dead】(ほんちゅ)発行の「超幸運ガール審神者GOLDEN」を買うなら、とらのあなJOSHIBU全年齢向け電子書籍!', $metadata->description);
|
||||
$this->assertRegExp('~ecdnimg\.toranoana\.jp/ec/img/.*\.jpg~', $metadata->image);
|
||||
if ($this->shouldUseMock()) {
|
||||
$this->assertSame('https://ec.toranoana.shop/joshi_d/digi/item/042000012192', (string) $this->handler->getLastRequest()->getUri());
|
||||
}
|
||||
}
|
||||
|
||||
public function testJoshiRD()
|
||||
{
|
||||
$responseText = file_get_contents(__DIR__ . '/../../fixture/Toranoana/testJoshiRD.html');
|
||||
|
||||
$this->createResolver(ToranoanaResolver::class, $responseText);
|
||||
|
||||
$metadata = $this->resolver->resolve('https://ec.toranoana.jp/joshi_rd/digi/item/042000013472');
|
||||
$this->assertEquals('UBWの裏側で非公式に遠坂凛をナデナデする本', $metadata->title);
|
||||
$this->assertEquals('サークル【阿仁谷組】(阿仁谷ユイジ)発行の「UBWの裏側で非公式に遠坂凛をナデナデする本」を買うなら、とらのあなJOSHIBU成年向け電子書籍!', $metadata->description);
|
||||
$this->assertRegExp('~ecdnimg\.toranoana\.jp/ec/img/.*\.jpg~', $metadata->image);
|
||||
if ($this->shouldUseMock()) {
|
||||
$this->assertSame('https://ec.toranoana.jp/joshi_rd/digi/item/042000013472', (string) $this->handler->getLastRequest()->getUri());
|
||||
}
|
||||
}
|
||||
}
|
51
tests/Unit/MetadataResolver/XtubeResolverTest.php
Normal file
51
tests/Unit/MetadataResolver/XtubeResolverTest.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\MetadataResolver;
|
||||
|
||||
use App\MetadataResolver\XtubeResolver;
|
||||
use Tests\TestCase;
|
||||
|
||||
class XtubeResolverTest extends TestCase
|
||||
{
|
||||
use CreateMockedResolver;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!$this->shouldUseMock()) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
$responseText = file_get_contents(__DIR__ . '/../../fixture/Xtube/test.json');
|
||||
|
||||
$this->createResolver(XtubeResolver::class, $responseText);
|
||||
|
||||
$metadata = $this->resolver->resolve('https://www.xtube.com/video-watch/homegrown-big-tits-18634762');
|
||||
$this->assertEquals('Homegrown Big Tits', $metadata->title);
|
||||
$this->assertEquals('Dedicated to the fans of the beautiful amateur women with big natural tits. All user submitted - you can see big boob amateur hotties fucking and sucking as their tits bounce and sway.', $metadata->description);
|
||||
$this->assertRegExp('~https://cdn\d-s-hw-e5\.xtube\.com/m=eSK08f/videos/201302/07/RF4Nk-S774-/240X180/1\.jpg~', $metadata->image);
|
||||
$this->assertEquals(['bigtits', 'homeg'], $metadata->tags);
|
||||
}
|
||||
|
||||
public function testNotMatch()
|
||||
{
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$this->expectExceptionMessage('Unmatched URL Pattern: https://www.xtube.com/gallery/black-celebs-free-7686657');
|
||||
|
||||
$this->createResolver(XtubeResolver::class, '');
|
||||
$this->resolver->resolve('https://www.xtube.com/gallery/black-celebs-free-7686657');
|
||||
}
|
||||
|
||||
public function testNotOK()
|
||||
{
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$this->expectExceptionMessage('404: https://www.xtube.com/video-watch/notfound-404');
|
||||
|
||||
$this->createResolver(XtubeResolver::class, '', [], 404);
|
||||
$this->resolver->resolve('https://www.xtube.com/video-watch/notfound-404');
|
||||
}
|
||||
}
|
228
tests/fixture/Pixiv/illustMultiPages.json
vendored
228
tests/fixture/Pixiv/illustMultiPages.json
vendored
File diff suppressed because one or more lines are too long
1675
tests/fixture/Toranoana/testJoshi.html
vendored
Normal file
1675
tests/fixture/Toranoana/testJoshi.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1588
tests/fixture/Toranoana/testJoshiD.html
vendored
Normal file
1588
tests/fixture/Toranoana/testJoshiD.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1738
tests/fixture/Toranoana/testJoshiR.html
vendored
Normal file
1738
tests/fixture/Toranoana/testJoshiR.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1696
tests/fixture/Toranoana/testJoshiRD.html
vendored
Normal file
1696
tests/fixture/Toranoana/testJoshiRD.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1794
tests/fixture/Toranoana/testTora.html
vendored
Normal file
1794
tests/fixture/Toranoana/testTora.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1674
tests/fixture/Toranoana/testToraD.html
vendored
Normal file
1674
tests/fixture/Toranoana/testToraD.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1744
tests/fixture/Toranoana/testToraR.html
vendored
Normal file
1744
tests/fixture/Toranoana/testToraR.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1626
tests/fixture/Toranoana/testToraRD.html
vendored
Normal file
1626
tests/fixture/Toranoana/testToraRD.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixture/Xtube/test.json
vendored
Normal file
1
tests/fixture/Xtube/test.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"duration":"180","views":3146,"video_id":"RF4Nk-S774-","rating":"4.000","ratings":"1","title":"Homegrown Big Tits","description":"Dedicated to the fans of the beautiful amateur women with big natural tits. All user submitted - you can see big boob amateur hotties fucking and sucking as their tits bounce and sway.","url":"https:\/\/www.xtube.com\/video-watch\/homegrown-big-tits-18634762","embedCode":"https:\/\/www.xtube.com\/video-watch\/embedded\/homegrown-big-tits-18634762","default_thumb":"https:\/\/cdn5-s-hw-e5.xtube.com\/m=eSuQ8f\/videos\/201302\/07\/RF4Nk-S774-\/240X180\/1.jpg","thumb":"https:\/\/cdn5-s-hw-e5.xtube.com\/m=eSuQ8f\/videos\/201302\/07\/RF4Nk-S774-\/240X180\/1.jpg","publish_date":"2013-02-07 17:41:10","tags":{"1396":"bigtits","472012":"homeg"},"thumbs":[{"width":300,"height":210,"src":"https:\/\/cdn4-s-hw-e5.xtube.com\/m=eSK08f\/videos\/201302\/07\/RF4Nk-S774-\/240X180\/1.jpg"},{"width":300,"height":210,"src":"https:\/\/cdn4-s-hw-e5.xtube.com\/m=eSK08f\/videos\/201302\/07\/RF4Nk-S774-\/240X180\/2.jpg"},{"width":300,"height":210,"src":"https:\/\/cdn10-s-hw-e5.xtube.com\/m=eSK08f\/videos\/201302\/07\/RF4Nk-S774-\/240X180\/3.jpg"}]}
|
@@ -2333,7 +2333,7 @@ d3@^3.0.6:
|
||||
resolved "https://registry.yarnpkg.com/d3/-/d3-3.5.17.tgz#bc46748004378b21a360c9fc7cf5231790762fb8"
|
||||
integrity sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=
|
||||
|
||||
date-fns@^1.27.2:
|
||||
date-fns@^1.27.2, date-fns@^1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
|
||||
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
|
||||
@@ -4607,9 +4607,9 @@ lodash.uniq@^4.5.0:
|
||||
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
|
||||
|
||||
lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5:
|
||||
version "4.17.11"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
||||
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
|
||||
log-symbols@^1.0.2:
|
||||
version "1.0.2"
|
||||
|
Reference in New Issue
Block a user