diff --git a/.idea/php.xml b/.idea/php.xml index b3ea71c..a763934 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -180,6 +180,8 @@ + + diff --git a/app/BilibiliVideos.php b/app/BilibiliVideos.php index 9e47d4b..15a5217 100644 --- a/app/BilibiliVideos.php +++ b/app/BilibiliVideos.php @@ -39,6 +39,12 @@ use Illuminate\Database\Eloquent\Model; * @method static \Illuminate\Database\Eloquent\Builder|\App\BilibiliVideos whereBvId($value) * @method static \Illuminate\Database\Eloquent\Builder|\App\BilibiliVideos whereCollectionMid($value) * @method static \Illuminate\Database\Eloquent\Builder|\App\BilibiliVideos whereUpMid($value) + * @property int $download_status 下载状态,0 表示未在下载中 1 表示下载中 + * @property int $encode_status 转码状态,0 表示未在转码中 1 表示转码中 + * @property int $version 版本号,用做乐观锁更新 + * @method static \Illuminate\Database\Eloquent\Builder|BilibiliVideos whereDownloadStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|BilibiliVideos whereEncodeStatus($value) + * @method static \Illuminate\Database\Eloquent\Builder|BilibiliVideos whereVersion($value) */ class BilibiliVideos extends Model { diff --git a/app/Console/Commands/BiliVideoCode.php b/app/Console/Commands/BiliVideoCode.php index 996757b..4d2ca5d 100644 --- a/app/Console/Commands/BiliVideoCode.php +++ b/app/Console/Commands/BiliVideoCode.php @@ -55,6 +55,8 @@ class BiliVideoCode extends Command // exit; $bilibili->queryDBCollectionList(); + // $bilibili->compareAndDownloadUpVideos(true); + // $bilibili->compareAndDownloadCollectionVideos(); // exit; $bilibili->queryForVideoParts(); if (App::environment() == "local") { diff --git a/app/Console/Commands/RecordDir.php b/app/Console/Commands/RecordDir.php new file mode 100644 index 0000000..720c72f --- /dev/null +++ b/app/Console/Commands/RecordDir.php @@ -0,0 +1,55 @@ +recursiveScan("/Users/shixuesen/Documents/sync/image"); + foreach ($list["files"] as $file) { + $fileInfo = pathinfo($file); + $imageRecord = new ImageRecord(); + $imageRecord->path = $fileInfo["dirname"]; + $imageRecord->name = $fileInfo["filename"]; + $imageRecord->type = 2; + $imageRecord->save(); + } + + } +} diff --git a/app/Http/Controllers/ImageRecordController.php b/app/Http/Controllers/ImageRecordController.php new file mode 100644 index 0000000..02ee374 --- /dev/null +++ b/app/Http/Controllers/ImageRecordController.php @@ -0,0 +1,85 @@ +update($attrs); + } + +} diff --git a/app/Services/BilibiliServiceV2.php b/app/Services/BilibiliServiceV2.php index e7851ef..20dcd37 100644 --- a/app/Services/BilibiliServiceV2.php +++ b/app/Services/BilibiliServiceV2.php @@ -6,6 +6,7 @@ namespace App\Services; use App\BilibiliCollections; use App\BilibiliUpVideos; use App\BilibiliVideoParts; +use App\BilibiliVideoRepository; use App\BilibiliVideos; use Exception; use GuzzleHttp\Client; @@ -27,7 +28,14 @@ class BilibiliServiceV2 private $baseDir = "/Volumes/intel660p/video/mv/"; - private $remoteDir = "/data"; + private $remoteDir = "/data/"; + + protected $repository; + + public function __construct(BilibiliVideoRepository $repository) + { + $this->repository = $repository; + } public function queryPlayList() { @@ -249,6 +257,10 @@ class BilibiliServiceV2 if ($item["is_downloaded"] == 1) { continue; } + if (!$this->checkDiskSpace()) { + Log::info('磁盘空间不足'); + exit; + } Log::info("schedule compareAndDownloadUpVideos current up is {$item['up_name']}, started at: " . date("Y-m-d H:i:s")); if ($isAll) { $vItems = BilibiliVideos::where("up_mid", $item["mid"])->get(); @@ -258,40 +270,59 @@ class BilibiliServiceV2 } $videoList = []; $videoPartsMap = []; - if (count($vItems) > 0) { - foreach ($vItems as $vItem) { - if ($vItem["is_download"] == 1 && $vItem["is_downloaded"] == 0) { + if (count($vItems) > 0) { + foreach ($vItems as $vItem) { + if ($vItem["is_download"] == 1 && $vItem["is_downloaded"] == 0 || $vItem["download_status"] != 1) { // $videoList[] = "av" . $vItem["aid"]; - $videoPartsMap = []; - $videoPartsMap[$vItem["aid"]] = $vItem["total_parts"]; - echo "当前 up名称是: " . $item["up_name"] . " 当前下载的视频 title: " . $vItem["title"] . " 当前下载的视频 aid 是:" . $vItem["aid"] . "\n" ; - Log::info("当前 up名称是: " . $item["up_name"] . " 当前下载的视频 title: " . $vItem["title"] . " 当前下载的视频 aid 是:" . $vItem["aid"]); - if ($env == "local") { - $result = false; - if ($item['mid'] == 27174777) { - $result = $this->partDownloadBSitePlaylist($videoPartsMap, "/Volumes/WD/tmp/bilibili/", "女团"); - } else if ($item["mid"] == 391316322) { - $result = $this->partDownloadBSitePlaylist($videoPartsMap, "/Volumes/WD/tmp/bilibili/", "娜娜"); - } else if ($item["mid"] == 396501206) { - $result = $this->partDownloadBSitePlaylist($videoPartsMap, "/Volumes/WD/tmp/bilibili/", "佳佳"); - } else { - $result = $this->partDownloadBSitePlaylist($videoPartsMap, $this->baseDir . "bilibili/", $item['up_name']); - } - if ($result) { - $vItem["is_downloaded"] = 1; - $vItem->save(); - } + if (!$this->repository->softLockUpdate(["id" => $vItem["id"]], $vItem["version"], ["download_status" => 1])) { + Log::warning("soft Lock failed id : " . $vItem["id"]); + continue; + } + + $videoPartsMap = []; + $videoPartsMap[$vItem["aid"]] = $vItem["total_parts"]; + echo "当前 up名称是: " . $item["up_name"] . " 当前下载的视频 title: " . $vItem["title"] . " 当前下载的视频 aid 是:" . $vItem["aid"] . "\n"; + Log::info("当前 up名称是: " . $item["up_name"] . " 当前下载的视频 title: " . $vItem["title"] . " 当前下载的视频 aid 是:" . $vItem["aid"]); + if ($env == "local") { + $result = false; + + if ($item['mid'] == 27174777) { + $result = $this->partDownloadBSitePlaylist($videoPartsMap, "/Volumes/WD/tmp/bilibili/", "女团"); + } else if ($item["mid"] == 391316322) { + $result = $this->partDownloadBSitePlaylist($videoPartsMap, "/Volumes/WD/tmp/bilibili/", "娜娜"); + } else if ($item["mid"] == 396501206) { + $result = $this->partDownloadBSitePlaylist($videoPartsMap, "/Volumes/WD/tmp/bilibili/", "佳佳"); } else { - $result = $this->partDownloadBSitePlaylist($videoPartsMap, $this->remoteDir . "bilibili/", $item["up_name"]); - if ($result) { - $vItem["is_downloaded"] = 1; - $vItem->save(); + $result = $this->partDownloadBSitePlaylist($videoPartsMap, $this->baseDir . "bilibili/", $item['up_name']); + } + if ($result) { + if (!$this->repository->softLockUpdate( + ["id" => $vItem["id"]], + $vItem["version"], + ["download_status" => 0, + "is_downloaded" => 1 + ])) { + Log::warning("soft Lock failed id : " . $vItem["id"]); + } + } + } else { + $result = $this->partDownloadBSitePlaylist($videoPartsMap, $this->remoteDir . "bilibili/", $item["up_name"]); + if ($result) { + if (!$this->repository->softLockUpdate( + ["id" => $vItem["id"]], + $vItem["version"], + ["download_status" => 0, + "is_downloaded" => 1 + ])) { + Log::warning("soft Lock failed id : " . $vItem["id"]); + } } } - } + } } + } } } @@ -304,6 +335,10 @@ class BilibiliServiceV2 if ($item["is_downloaded"] == 1) { continue; } + if (!$this->checkDiskSpace()) { + Log::info('磁盘空间不足'); + exit; + } Log::info("schedule compareAndDownloadCollectionVideos current collection is {$item['title']}, started at: " . date("Y-m-d H:i:s")); $videoList = []; $videoPartsMap = []; @@ -317,11 +352,15 @@ class BilibiliServiceV2 if (count($vItems) > 0) { foreach ($vItems as $vItem) { - if ($vItem["is_download"] == 1 && $vItem["is_downloaded"] == 0) { + if ($vItem["is_download"] == 1 && $vItem["is_downloaded"] == 0 && $vItem["download_status"] == 0) { // $videoList[] = "av" . $vItem["aid"]; + if (!$this->repository->softLockUpdate(["id" => $vItem["id"]], $vItem["version"], ["download_status" => 1])) { + Log::warning("soft Lock failed id : " . $vItem["id"]); + continue; + } $videoPartsMap = []; $videoPartsMap[$vItem["aid"]] = $vItem["total_parts"]; - echo "收藏夹名称是: " . $item["title"] . " 当前下载的视频 title: " . $vItem["title"] . " 当前下载的视频 aid 是:" . $vItem["aid"] . "\n" ; + echo "收藏夹名称是: " . $item["title"] . " 当前下载的视频 title: " . $vItem["title"] . " 当前下载的视频 aid 是:" . $vItem["aid"] . "\n"; Log::info("收藏夹名称是: " . $item["title"] . " 当前下载的视频 title: " . $vItem["title"] . " 当前下载的视频 aid 是:" . $vItem["aid"]); if ($env == "local") { $result = false; @@ -340,17 +379,28 @@ class BilibiliServiceV2 $result = $this->partDownloadBSitePlaylist($videoPartsMap, $this->baseDir . "bilibili/", $item['title']); } if ($result) { - $vItem["is_downloaded"] = 1; - $vItem->save(); + if (!$this->repository->softLockUpdate( + ["id" => $vItem["id"]], + $vItem["version"], + ["download_status" => 0, + "is_downloaded" => 1 + ])) { + Log::warning("soft Lock failed id : " . $vItem["id"]); + } } } else { $result = $this->partDownloadBSitePlaylist($videoPartsMap, $this->remoteDir . "bilibili", $item["title"]); if ($result) { - $vItem["is_downloaded"] = 1; - $vItem->save(); + if (!$this->repository->softLockUpdate( + ["id" => $vItem["id"]], + $vItem["version"], + ["download_status" => 0, + "is_downloaded" => 1 + ])) { + Log::warning("soft Lock failed id : " . $vItem["id"]); + } } } - } } } @@ -678,8 +728,8 @@ class BilibiliServiceV2 $dirFiles = []; $dirFiles["/Volumes/WD/tmp/bilibili"] = scandir("/Volumes/WD/tmp/bilibili"); $dirFiles["/Volumes/WD/tmp/bilibili/aoa"] = scandir("/Volumes/WD/tmp/bilibili/aoa"); - $dirFiles["/Volumes/WD/tmp/bilibili/女团"]= scandir("/Volumes/WD/tmp/bilibili/女团"); - $dirFiles["/Volumes/WD/tmp/bilibili/少女时代"]= scandir("/Volumes/WD/tmp/bilibili/少女时代"); + $dirFiles["/Volumes/WD/tmp/bilibili/女团"] = scandir("/Volumes/WD/tmp/bilibili/女团"); + $dirFiles["/Volumes/WD/tmp/bilibili/少女时代"] = scandir("/Volumes/WD/tmp/bilibili/少女时代"); while ($list->isNotEmpty()) { foreach ($list->items() as $item) { // dump("current item", [$item->getAttributes()]); @@ -743,8 +793,8 @@ class BilibiliServiceV2 $dirFiles = []; $dirFiles["/Volumes/WD/tmp/bilibili"] = scandir("/Volumes/WD/tmp/bilibili"); $dirFiles["/Volumes/WD/tmp/bilibili/aoa"] = scandir("/Volumes/WD/tmp/bilibili/aoa"); - $dirFiles["/Volumes/WD/tmp/bilibili/女团"]= scandir("/Volumes/WD/tmp/bilibili/女团"); - $dirFiles["/Volumes/WD/tmp/bilibili/少女时代"]= scandir("/Volumes/WD/tmp/bilibili/少女时代"); + $dirFiles["/Volumes/WD/tmp/bilibili/女团"] = scandir("/Volumes/WD/tmp/bilibili/女团"); + $dirFiles["/Volumes/WD/tmp/bilibili/少女时代"] = scandir("/Volumes/WD/tmp/bilibili/少女时代"); while ($list->isNotEmpty()) { foreach ($list->items() as $item) { dump("current item", [$item->getAttributes()]); @@ -770,7 +820,7 @@ class BilibiliServiceV2 if ($file == "." || $file == "..") { continue; } else { - dump("current file: ". $file ." ".$part["title"]); + dump("current file: " . $file . " " . $part["title"]); $pos = strpos($file, $part["title"]); // dump("current compare result " . $pos); if ($pos !== false) { @@ -874,7 +924,7 @@ class BilibiliServiceV2 } foreach ($aidList as $aid) { Log::info("current download command is : cd '{$innerDir}' && annie -r https://www.bilibili.com/video/av80815149 -p " . $aid); - $downloadResult = shell_exec('cd "' .$innerDir .'" && annie -r https://www.bilibili.com/video/av80815149 -p ' . $aid); + $downloadResult = shell_exec('cd "' . $innerDir . '" && annie -r https://www.bilibili.com/video/av80815149 -p ' . $aid); Log::info($downloadResult); Log::info("current download result: " . $downloadResult); try { @@ -896,14 +946,19 @@ class BilibiliServiceV2 $env = App::environment(); $dirExists = is_dir($dir); dump($dirExists); + echo "dir is $dir, and $dirExists"; if ($dirExists) { $innerDir = $dir . "/" . $subDir; dump($innerDir); if (!is_dir($innerDir)) { mkdir($innerDir); } + if (!$this->checkDiskSpace($innerDir)) { + Log::info('磁盘空间不足'); + exit; + } echo "当前视频的下载路径是: " . $innerDir . "\n"; - Log::info("当前视频的下载路径是: " . $innerDir ); + Log::info("当前视频的下载路径是: " . $innerDir); foreach ($aidMap as $aid => $parts) { dump($aid); Log::info("current download command is : cd '{$innerDir}' && annie -r https://www.bilibili.com/video/av80815149 -p " . $aid); @@ -985,7 +1040,7 @@ done && echo "ok"'); $aNo = 484525; for ($i = 0; $i < 5000000; $i++) { $tempANo = $aNo + $i; - $sql = "insert into `bilibili_video_temps`( `aid`, `title`, `from_type`, `from_collection_name`, `from_up_name`, `is_download`, `is_downloaded`, `total_parts`, `created_at`, `updated_at`) VALUES ( " .$tempANo . ", '【钢琴】《鬼灭之刃》OP《红莲华》by LiSA', 2, '', '绯绯', 1, 1, 1, '2020-01-08 10:05:40', '2020-01-13 23:35:17');"; + $sql = "insert into `bilibili_video_temps`( `aid`, `title`, `from_type`, `from_collection_name`, `from_up_name`, `is_download`, `is_downloaded`, `total_parts`, `created_at`, `updated_at`) VALUES ( " . $tempANo . ", '【钢琴】《鬼灭之刃》OP《红莲华》by LiSA', 2, '', '绯绯', 1, 1, 1, '2020-01-08 10:05:40', '2020-01-13 23:35:17');"; $result = DB::insert($sql); if ($i % 100 == 0) { print_r($result); @@ -996,7 +1051,15 @@ done && echo "ok"'); public function searchVideoFiles($filename) { - $list = BilibiliVideos::where("title", "like", "%". trim($filename) ."%" )->get(); + $list = BilibiliVideos::where("title", "like", "%" . trim($filename) . "%")->get(); dump($list); } + + public function checkDiskSpace($dir = "/data") + { + if (disk_free_space($dir) > 5 * 1024 * 1024 * 1024) { + return true; + } + return false; + } } diff --git a/app/Services/DirService.php b/app/Services/DirService.php new file mode 100644 index 0000000..7673763 --- /dev/null +++ b/app/Services/DirService.php @@ -0,0 +1,180 @@ + $files, 'dirs' => $dirs); + } + + public function recursiveScan($dir) { + $files = array(); + $dirs = array(); + if (is_dir($dir)) { + if ($dh = opendir($dir)) { + while (($file = readdir($dh)) !== false) { + if ($file != '.' && $file != '..') { + if (is_dir($dir . DIRECTORY_SEPARATOR . $file)) { + $dirs[] = $file; + $tempResult = $this->recursiveScan($dir . DIRECTORY_SEPARATOR . $file); + $dirs = array_merge($dirs, $tempResult['dirs']); + $files = array_merge($files, $tempResult['files']); + } else { + $files[] = $dir . DIRECTORY_SEPARATOR . $file; + } + } + } + closedir($dh); + } + } + return array('files' => $files, 'dirs' => $dirs); + } + + + + + + + + /** + * 扫描目录下所有文件, + * @var array + */ + protected static $files = []; + + public static $ret = []; + + /** + * 扫描目录路径 + * @param $path string 带扫描的路径 + * @param array $options 要附加的选项,后面可以根据自己需求扩展 + * @return array + * @author: Vencenty + */ + static function scan($path, $options = []) + { + $options = array_merge([ + 'callback' => null, // 对查找到的文件进行操作 + 'filterExt' => [], // 要过滤的文件后缀 + ], $options); + + $scanQueue = [$path]; + + while (count($scanQueue) != 0) { + $rootPath = array_pop($scanQueue); + + // 过滤['.', '..']目录 + $paths = array_filter(scandir($rootPath), function ($path) { + return !in_array($path, ['.', '..']); + }); + + foreach ($paths as $path) { + // 拼接完整路径 + $fullPath = $rootPath . DIRECTORY_SEPARATOR . $path; + // 如果是目录的话,合并到扫描队列中继续进行扫描 + if (is_dir($fullPath)) { + array_unshift($scanQueue, $fullPath); + continue; + } + + // 如果不是空,进行过滤 + if (!empty($options['filterExt'])) { + $pathInfo = pathinfo($fullPath); + $ext = $pathInfo['extension'] ?? null; + if (in_array($ext, $options['filterExt'])) { + continue; + } + } + + if ($options['callback'] instanceof Closure) { + // 经过callback处理之后为空的数据不作处理 + $fullPath = $options['callback']($fullPath); + // 返回的只要不是字符串路径,不作处理 + if (!is_string($fullPath)) { + continue; + } + } + + array_push(static::$files, $fullPath); + } + } + + return static::$files; + } + + /** + * 目录拷贝,返回被拷贝的文件数, + * @param $source string 源文件,填写绝对路径 + * @param $dest string 目标路径,填写绝对路径 + * @param $force bool 开启会每次强制覆盖原文件,false不进行覆盖,存在文件不做处理 + * @return int 拷贝的文件数 + * @author: Vencenty + */ + static function copy($source, $dest, $force = true) + { + static $counter = 0; + $paths = array_filter(scandir($source), function ($file) { + return !in_array($file, ['.', '..']); + }); + + foreach ($paths as $path) { + // 要拷贝的源文件的完整路径 + $sourceFullPath = $source . DIRECTORY_SEPARATOR . $path; + // 要拷贝到的文件的路径 + $destFullPath = $dest . DIRECTORY_SEPARATOR . $path; + + // 拷贝的目标地址如果是不是文件夹,那么说明文件夹不存在,那么首先创建文件夹 + if (is_dir($sourceFullPath)) { + if (!is_dir($destFullPath)) { + mkdir($destFullPath); + chmod($destFullPath, 0755); + } + // 递归copy + static::copy($sourceFullPath, $destFullPath, $force); + continue; + } + + // 不开启强制覆盖的话如果已经存在文件了那么直接跳过,不进行处理 + if (!$force && file_exists($destFullPath)) { + continue; + } + + // 每次copy成功文件计数器+1 + if (copy($sourceFullPath, $destFullPath)) { + $counter++; + } + } + + return $counter; + } +} +// $path = realpath('../'); +// $r = Dir::scan($path, [ +// 'callback' => function ($file) { +// return filemtime($file) > strtotime('-1 day') ? $file : null; // 查找修改过的文件 +// }, +// 'filterExt' => [] +// ]); +// //print_r($r); + +// $r = Dir::copy('C:\phpStudy\PHPTutorial\WWW\php\.idea', 'C:\phpStudy\PHPTutorial\WWW\php', true); +// print_r($r); diff --git a/app/Services/FfmpegService.php b/app/Services/FfmpegService.php index 7dc537c..4c7522e 100644 --- a/app/Services/FfmpegService.php +++ b/app/Services/FfmpegService.php @@ -107,6 +107,14 @@ class FfmpegService exit; } $fileInfo = pathinfo($pathFile); + if (Redis::get("encode:lock:" . $fileInfo["filename"]) == 1) { + Log::info("file is encoding filename: " . $fileInfo["filename"]); + return; + } + if (!Redis::set("encode:lock:" . $fileInfo["filename"] , 1, "nx", "ex", 36000)) { + Log::info("lock failed filename: " . $fileInfo["filename"]); + return; + } if (Redis::sismember("unneed", $fileInfo["filename"])) { return; } @@ -156,6 +164,7 @@ class FfmpegService rename($targetFile, $pathFile); } } + Redis::del("encode:lock:" . $fileInfo["filename"]); } } } diff --git a/app/Services/NewNvshenService.php b/app/Services/NewNvshenService.php index ef50ee1..54c95a4 100644 --- a/app/Services/NewNvshenService.php +++ b/app/Services/NewNvshenService.php @@ -158,12 +158,17 @@ class NewNvshenService if ($isAll) { $countLimit = 5000; } - for ($i = 0; $i <= $totalAlbumPage; $i++) { + for ($i = 1; $i <= $totalAlbumPage; $i++) { dump("current album page no: " . $i); if ($onlyOnePage) { $albumQl = $mainQl->get($peopleUrl); } else { - $albumQl = $mainQl->get($baseAlbumUrl . $i . ".html"); + if ($i == 1) { + $albumQl = $mainQl->get($baseAlbumUrl); + } else { + $albumQl = $mainQl->get($baseAlbumUrl . $i . ".html"); + } + } // dump($albumQl->getHtml()); $albumList = $albumQl->find(".igalleryli > .igalleryli_div > .igalleryli_link")->attrs("href"); diff --git a/app/Services/XiurenjiService.php b/app/Services/XiurenjiService.php index e64d40b..ce342be 100644 --- a/app/Services/XiurenjiService.php +++ b/app/Services/XiurenjiService.php @@ -11,8 +11,8 @@ use QL\QueryList; class XiurenjiService { - public $domainUrl = "https://www.xiurenji.vip"; - public $xiurenRootUrl = "https://www.xiurenji.vip/XiuRen/"; + public $domainUrl = "https://www.xiurenji.net"; + public $xiurenRootUrl = "https://www.xiurenji.net/XiuRen/"; // public $rootDir = "/Users/shixuesen/Documents/tmp/xiuren/"; // public $rootDir = "/Volumes/Backup/images/xiuren/"; public $rootDir = "/Volumes/intel660p/image/xiuren/"; @@ -27,7 +27,7 @@ class XiurenjiService public function scrapeAlbum() { $pageSize = 20; - $pageCount = $this->getEncodeHtmlContent("https://www.xiurenji.vip/XiuRen/index.html")->find(".page span")->htmls()->get(0); + $pageCount = $this->getEncodeHtmlContent("https://www.xiurenji.net/XiuRen/index.html")->find(".page span")->htmls()->get(0); print_r($pageCount); if ((int)$pageCount > 0) { $pageCount = 100; @@ -126,7 +126,7 @@ class XiurenjiService usleep(random_int(10, 100) * 100); $imageUrl = $image->getAttribute("src"); $trueImageUrl = "https://x1.plmn5.com/U". substr($imageUrl, 2); - $trueImageUrl = "https://www.xiurenji.vip" . $imageUrl; + $trueImageUrl = "https://www.xiurenji.net" . $imageUrl; $fileInfo = pathinfo($trueImageUrl); if (file_exists($dir . "/" .$fileInfo["basename"])) { rename($dir . "/" . $fileInfo["basename"], $dir . "/" . $imageNo . "-" . $fileInfo["basename"]); @@ -149,11 +149,32 @@ class XiurenjiService try { $curl_handle=curl_init(); curl_setopt($curl_handle, CURLOPT_URL, $trueImageUrl); - curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2000); + curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 20000); curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl_handle, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'); curl_setopt($curl_handle, CURLOPT_REFERER, $this->xiurenRootUrl); curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl_handle, CURLOPT_ENCODING, ''); + curl_setopt($curl_handle, CURLOPT_MAXREDIRS, 10); + curl_setopt($curl_handle, CURLOPT_TIMEOUT, 0); + curl_setopt($curl_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); + curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'GET'); + curl_setopt($curl_handle, CURLOPT_HTTPHEADER, array( + 'authority: www.xiurenji.net', + 'pragma: no-cache', + 'cache-control: no-cache', + 'sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"', + 'sec-ch-ua-mobile: ?0', + 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36', + 'sec-ch-ua-platform: "macOS"', + 'accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8', + 'sec-fetch-site: same-origin', + 'sec-fetch-mode: no-cors', + 'sec-fetch-dest: image', + 'referer: https://www.xiurenji.net/XiuRen/9483.html', + 'accept-language: zh-CN,zh;q=0.9', + 'cookie: UM_distinctid=17cfa8bea8eb9e-0dd0c6d032d0fc-1c306851-13c680-17cfa8bea8fc85; CNZZDATA1278618868=1505121253-1636283360-%7C1636283360; __51cke__=; ASPSESSIONIDQAQAATSQ=LBLGNPMDHKKMNOPDBCEAPIMH; __tins__20641871=%7B%22sid%22%3A%201636291046220%2C%20%22vd%22%3A%202%2C%20%22expires%22%3A%201636292852634%7D; __51laig__=2' + )); $content = curl_exec($curl_handle); if ($content === false) { $le = new Exception("get image has error: " . curl_error($curl_handle)); @@ -210,7 +231,7 @@ class XiurenjiService CURLOPT_SSL_VERIFYHOST => false, CURLOPT_HTTPHEADER => array( - 'authority: www.xiurenji.vip', + 'authority: www.xiurenji.net', 'pragma: no-cache', 'cache-control: no-cache', 'sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="91", "Chromium";v="91"', @@ -222,7 +243,7 @@ class XiurenjiService 'sec-fetch-mode: navigate', 'sec-fetch-user: ?1', 'sec-fetch-dest: document', - 'referer: https://www.xiurenji.vip/XiuRen/', + 'referer: https://www.xiurenji.net/XiuRen/', 'accept-language: zh-CN,zh;q=0.9', 'cookie: UM_distinctid=177fd93a0ca93c-06b94658d5d337-121a4759-13c680-177fd93a0cbcaf; ASPSESSIONIDCATDQACD=FDPMPCLAMHNCPJFCBLKFLCKH; CNZZDATA1278618868=367774893-1614867004-%7C1625926983; __51cke__=; __tins__20641871=%7B%22sid%22%3A%201625931982756%2C%20%22vd%22%3A%203%2C%20%22expires%22%3A%201625933829110%7D; __51laig__=7' ), diff --git a/composer.json b/composer.json index ad35dd0..2279540 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,7 @@ "netresearch/jsonmapper": "^1.6", "norkunas/youtube-dl-php": "^1.4", "php-ffmpeg/php-ffmpeg": "^0.18.0", + "prettus/l5-repository": "dev-master", "protoqol/prequel": "^1.22", "ps/image-optimizer": "^2.0", "qcloud/cos-sdk-v5": ">=1.0", diff --git a/composer.lock b/composer.lock index d940139..5d031b5 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "c7229f1acc25872366cc3bcf890dddc8", + "content-hash": "783aef1da9b015e3f7e49b63fac3fc55", "packages": [ { "name": "albertofem/rsync-lib", @@ -6226,6 +6226,142 @@ ], "time": "2021-09-29T17:48:39+00:00" }, + { + "name": "prettus/l5-repository", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/andersao/l5-repository.git", + "reference": "834d61f0d5d9b6ef5786980e0bf4900fffbccd76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/andersao/l5-repository/zipball/834d61f0d5d9b6ef5786980e0bf4900fffbccd76", + "reference": "834d61f0d5d9b6ef5786980e0bf4900fffbccd76", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "illuminate/config": "~5.0|~6.0|~7.0|^8.0", + "illuminate/console": "~5.0|~6.0|~7.0|^8.0", + "illuminate/database": "~5.0|~6.0|~7.0|^8.0", + "illuminate/filesystem": "~5.0|~6.0|~7.0|^8.0", + "illuminate/http": "~5.0|~6.0|~7.0|^8.0", + "illuminate/pagination": "~5.0|~6.0|~7.0|^8.0", + "illuminate/support": "~5.0|~6.0|~7.0|^8.0", + "illuminate/validation": "~5.0|~6.0|~7.0|^8.0", + "prettus/laravel-validation": "~1.1|~1.2" + }, + "suggest": { + "league/fractal": "Required to use the Fractal Presenter (0.12.*).", + "prettus/laravel-validation": "Required to provide easy validation with the repository (1.1.*)", + "robclancy/presenter": "Required to use the Presenter Model (1.3.*)" + }, + "default-branch": true, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Prettus\\Repository\\Providers\\RepositoryServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Prettus\\Repository\\": "src/Prettus/Repository/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anderson Andrade", + "email": "contato@andersonandra.de", + "homepage": "http://andersonandra.de", + "role": "Developer" + } + ], + "description": "Laravel 5|6|7|8 - Repositories to the database layer", + "homepage": "http://andersao.github.io/l5-repository", + "keywords": [ + "cache", + "eloquent", + "laravel", + "model", + "repository" + ], + "support": { + "docs": "http://andersao.github.io/l5-repository", + "email": "contato@andersonandra.de", + "issues": "https://github.com/andersao/l5-repository/issues", + "source": "https://github.com/andersao/l5-repository", + "wiki": "https://github.com/andersao/l5-repository" + }, + "time": "2021-10-14T23:03:30+00:00" + }, + { + "name": "prettus/laravel-validation", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/andersao/laravel-validator.git", + "reference": "cce3c273c9d44f77de031dc4dedd261ab936c497" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/andersao/laravel-validator/zipball/cce3c273c9d44f77de031dc4dedd261ab936c497", + "reference": "cce3c273c9d44f77de031dc4dedd261ab936c497", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "illuminate/support": "~5.4|^6.0|^7.0|^8.0", + "illuminate/validation": "~5.4|^6.0|^7.0|^8.0", + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Prettus\\Validator\\": "src/Prettus/Validator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "authors": [ + { + "name": "Anderson Andrade", + "email": "contato@andersonandra.de", + "homepage": "http://andersonandra.de", + "role": "Developer" + } + ], + "description": "Laravel Validation Service", + "homepage": "http://andersao.github.io/laravel-validation", + "keywords": [ + "laravel", + "service", + "validation" + ], + "support": { + "docs": "http://andersao.github.io/laravel-validation", + "email": "contato@andersonandra.de", + "issues": "https://github.com/andersao/laravel-validation/issues", + "source": "https://github.com/andersao/laravel-validation", + "wiki": "https://github.com/andersao/laravel-validation" + }, + "time": "2020-09-21T20:20:45+00:00" + }, { "name": "protoqol/prequel", "version": "v1.22.61", @@ -12878,7 +13014,8 @@ "minimum-stability": "dev", "stability-flags": { "league/oauth2-client": 20, - "mgp25/instagram-php": 20 + "mgp25/instagram-php": 20, + "prettus/l5-repository": 20 }, "prefer-stable": true, "prefer-lowest": false, diff --git a/database/factories/ImageRecordFactory.php b/database/factories/ImageRecordFactory.php new file mode 100644 index 0000000..d69665d --- /dev/null +++ b/database/factories/ImageRecordFactory.php @@ -0,0 +1,9 @@ +define(App\ImageRecord::class, function (Faker $faker) { + return [ + // + ]; +}); diff --git a/database/migrations/2021_10_08_163234_create_google_photos_table.php b/database/migrations/2021_10_08_163234_create_google_photos_table.php index abc3f97..53a6cb5 100644 --- a/database/migrations/2021_10_08_163234_create_google_photos_table.php +++ b/database/migrations/2021_10_08_163234_create_google_photos_table.php @@ -13,14 +13,17 @@ class CreateGooglePhotosTable extends Migration */ public function up() { - Schema::create('google_photos', function (Blueprint $table) { - $table->increments('id'); - $table->string("photo_id"); - $table->string("filename"); - $table->string("product_url"); - $table->timestamp("creation_time"); - $table->timestamps(); - }); + if (!Schema::hasTable('google_photos')) { + Schema::create('google_photos', function (Blueprint $table) { + $table->increments('id'); + $table->string("photo_id"); + $table->string("filename"); + $table->string("product_url"); + $table->timestamp("creation_time"); + $table->timestamps(); + }); + } + } /** diff --git a/database/migrations/2021_10_08_165821_create_google_photos_table.php b/database/migrations/2021_10_08_165821_create_google_photos_table.php index f1ad830..778aae6 100644 --- a/database/migrations/2021_10_08_165821_create_google_photos_table.php +++ b/database/migrations/2021_10_08_165821_create_google_photos_table.php @@ -13,10 +13,13 @@ class CreateGooglePhotosTable extends Migration */ public function up() { - Schema::create('google_photos', function (Blueprint $table) { - $table->increments('id'); - $table->timestamps(); - }); + if (!Schema::hasTable('google_photos')) { + Schema::create('google_photos', function (Blueprint $table) { + $table->increments('id'); + $table->timestamps(); + }); + } + } /** diff --git a/database/migrations/2021_11_08_132032_create_image_records_table.php b/database/migrations/2021_11_08_132032_create_image_records_table.php new file mode 100644 index 0000000..8cd7729 --- /dev/null +++ b/database/migrations/2021_11_08_132032_create_image_records_table.php @@ -0,0 +1,34 @@ +increments('id'); + $table->string('name'); + $table->string('path'); + $table->tinyInteger('type')->comment("1: 目录 2: 文件"); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('image_records'); + } +} diff --git a/database/migrations/2021_11_24_133249_add_download_and_encode_status.php b/database/migrations/2021_11_24_133249_add_download_and_encode_status.php new file mode 100644 index 0000000..6efd623 --- /dev/null +++ b/database/migrations/2021_11_24_133249_add_download_and_encode_status.php @@ -0,0 +1,35 @@ +unsignedTinyInteger("download_status")->after("total_parts")->comment("下载状态,0 表示未在下载中 1 表示下载中")->default(0); + $table->unsignedTinyInteger("encode_status")->after("download_status")->comment("转码状态,0 表示未在转码中 1 表示转码中")->default(0); + $table->integer("version")->after("encode_status")->comment("版本号,用做乐观锁更新")->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('bilibili_videos', function (Blueprint $table) { + // + }); + } +} diff --git a/fail.log b/fail.log index 513f181..b1e56a9 100644 --- a/fail.log +++ b/fail.log @@ -2382,3 +2382,17 @@ /Users/shixuesen/OneDrive/Pictures/instagram/amandacerny/ https://scontent-lax3-2.cdninstagram.com/v/t50.12441-16/245270156_4510623145652065_114301360091157778_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5zdG9yeS5iYXNlbGluZSJ9&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=101&_nc_ohc=SXnJS1YXP3QAX8CHOpk&edm=AOVtZ6oBAAAA&vs=1870059469864735_3599376607&_nc_vs=HBksFQAYJEdJeUduZzVoNzA5S1l3WVFBQkxWa3oxN0ZKWUJicGt3QUFBRhUAAsgBABUAGCRHQW9sblE0cjZWQ19YejhFQUFCc1c4a2o0R0VxYnBrd0FBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMRUAACbWzL7249%2F%2BPxUCKAJDMywXQC4AAAAAAAAYEmRhc2hfYmFzZWxpbmVfMV92MREAdegHAA%3D%3D&_nc_rid=f7c6ea7c99&ccb=7-4&oe=616B6CD8&oh=6903fb4645c9bebc3a9c41a0075ef9cc&_nc_sid=bab638&_nc_vts_prog=1&vts=1 /Users/shixuesen/OneDrive/Pictures/instagram/Likes/ https://scontent-lax3-2.cdninstagram.com/v/t51.2885-15/e35/245796969_121234556967162_1605669378150390448_n.jpg?se=7&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=106&_nc_ohc=9LnckT_e3hcAX-ZZY6F&edm=APv5SkIBAAAA&ccb=7-4&oh=6331148356f76a70d2dfc03cb3d51b0b&oe=616F9316&_nc_sid=7479f6&ig_cache_key=MjY4NDIzMDAzMTEzOTgyMzEwNg%3D%3D.2-ccb7-4 /Users/shixuesen/OneDrive/Pictures/instagram/parlovetati/ https://scontent-lax3-1.cdninstagram.com/v/t50.2886-16/10000000_1240125606501674_5676588287682701350_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5mZWVkLmRlZmF1bHQifQ&_nc_ht=scontent-lax3-1.cdninstagram.com&_nc_cat=102&_nc_ohc=QEOWaUZJHc8AX_nGqBd&edm=ABmJApABAAAA&vs=18167405827164894_2723734113&_nc_vs=HBksFQAYJEdJQ1dtQUFxblVBXzQyY0VBQ1pvZU1mNFNzZE9ia1lMQUFBRhUAAsgBABUAGCRHUElLekE1SW1VYk1Na1FCQUxabXNRcnczeU5mYmtZTEFBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMBUAACbm2Zuu863KPxUCKAJDMywXQEyAAAAAAAAYEmRhc2hfYmFzZWxpbmVfMl92MREAdeoHAA%3D%3D&_nc_rid=29492f4664&ccb=7-4&oe=617879C0&oh=f53d7a889e63f284ab2106dc448b9de4&_nc_sid=6136e7 +/Users/shixuesen/OneDrive/Pictures/instagram/ngoctrinh89/ https://scontent-lax3-2.cdninstagram.com/v/t50.2886-16/254693390_614941546590078_7945511200483749374_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5jbGlwcy5iYXNlbGluZSJ9&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=106&_nc_ohc=X_dPMuTY_oYAX-0gBrm&edm=ABmJApABAAAA&vs=2198644710292468_3438973239&_nc_vs=HBksFQAYJEdBNVFMZzlfTDNFOFNTOENBUDZ0dVBkV0lFUnVicV9FQUFBRhUAAsgBABUAGCRHTUpwS2dfdFY2LTNqeUlDQUZJQmQ4QzhjT2RaYnFfRUFBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMBUAACa2hZW2voLaPxUCKAJDMywXQDZEGJN0vGoYEmRhc2hfYmFzZWxpbmVfMV92MREAdf4HAA%3D%3D&_nc_rid=46aeb30028&ccb=7-4&oe=618A3786&oh=26a129af56c4ef9eac6304693010a661&_nc_sid=6136e7 +/Users/shixuesen/OneDrive/Pictures/instagram/parlovetati/ https://scontent-lax3-2.cdninstagram.com/v/t51.2885-15/e35/255166477_613867276318659_6041843099943784371_n.jpg?se=7&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=103&_nc_ohc=Es6RcI6uvecAX-xdPah&edm=ABmJApABAAAA&ccb=7-4&oh=4e450b1fd0495e6b5c78ff45a5b77108&oe=618FC6BC&_nc_sid=6136e7&ig_cache_key=MjcwMTc2NTI2NzgzNDIwMjgzOQ%3D%3D.2-ccb7-4 +/Users/shixuesen/OneDrive/Pictures/instagram/ngoctrinh89/ https://scontent-lax3-1.cdninstagram.com/v/t50.2886-16/10000000_585662186093909_4096738381600548513_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5jbGlwcy5iYXNlbGluZSJ9&_nc_ht=scontent-lax3-1.cdninstagram.com&_nc_cat=105&_nc_ohc=uL2Sy0jHAZ4AX-PDa_V&edm=ABmJApABAAAA&vs=881083732587817_2799381338&_nc_vs=HBksFQAYJEdJQ1dtQUJWZlk4YXFCUUNBS0ZtQWtYYWlkbzRicV9FQUFBRhUAAsgBABUAGCRHTDlSTGc5OWNpaGNVSE1CQUoyM1ctLXQ0Z05fYnFfRUFBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMBUAACbIkPeoyt6%2FPxUCKAJDMywXQD%2F3S8an754YEmRhc2hfYmFzZWxpbmVfMV92MREAdf4HAA%3D%3D&_nc_rid=3441d0c3a1&ccb=7-4&oe=618BECF5&oh=2e56cb06a316b6e6d9f0a8f1579091c3&_nc_sid=6136e7 +/Users/shixuesen/OneDrive/Pictures/instagram/cherry_quahst/ https://scontent-lax3-1.cdninstagram.com/v/t50.12441-16/255531810_1083048569133861_5258824205722722467_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjY0MC5zdG9yeS5iYXNlbGluZSJ9&_nc_ht=scontent-lax3-1.cdninstagram.com&_nc_cat=109&_nc_ohc=GXrgCC1NWp4AX_3g3Hs&edm=AOVtZ6oBAAAA&vs=419989946323964_1351106573&_nc_vs=HBksFQAYJEdDSWJPdzhsMnp6bEJ0a0RBS01nVks3QUdQdElicGt3QUFBRhUAAsgBABUAGCRHQ3VpTVEtOGw1aXZYaFVEQUN5S3JsTDJqQjFMYnBrd0FBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMRUAACa2o%2B6Z%2BMa2PxUCKAJDMywXQC0Q5WBBiTcYEmRhc2hfYmFzZWxpbmVfMV92MREAdegHAA%3D%3D&_nc_rid=f7dce76b9c&ccb=7-4&oe=618D6980&oh=747be2e2ec37ef246704cf21bfb6bac7&_nc_sid=bab638 +/Users/shixuesen/OneDrive/Pictures/instagram/amandacerny/ https://scontent-lax3-2.cdninstagram.com/v/t50.2886-16/10000000_626056855089192_6276854772659920905_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5jbGlwcy5iYXNlbGluZSJ9&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=100&_nc_ohc=-9cF5HDzyDUAX_pu5tx&edm=ABmJApABAAAA&vs=567608327873432_3854848594&_nc_vs=HBksFQAYJEdJQ1dtQUFvOEhRNFpUa0NBQWtnSE5jbzNodFhicV9FQUFBRhUAAsgBABUAGCRHTFZyS2c4dGwzTVl3M2NBQUtZUEp6ZGt2MU1rYnFfRUFBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMBUAACb8robmuLHGQBUCKAJDMywXQE4AAAAAAAAYEmRhc2hfYmFzZWxpbmVfMV92MREAdf4HAA%3D%3D&_nc_rid=f35686a2bb&ccb=7-4&oe=618DB80E&oh=9ee18b4376abaa6f83c073214d393518&_nc_sid=6136e7 +/Users/shixuesen/OneDrive/Pictures/instagram/kiyocosplay/ https://scontent-lax3-2.cdninstagram.com/v/t50.16885-16/10000000_1294665354386099_2594239050078212671_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5pZ3R2LmRlZmF1bHQifQ&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=111&_nc_ohc=1-moooSC014AX8Lj4Bq&edm=ABmJApABAAAA&vs=17948680876583600_2297443186&_nc_vs=HBksFQAYJEdJQ1dtQUN6R28zRWZaa0VBRC1TVzlLcmxnQWtidlZCQUFBRhUAAsgBABUAGCRHT1JXTnc4N2NlVHk5Y1lEQUpJWC1NWHJlVXd0YnZWQkFBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMRUAACau5cz8xtbmPxUCKAJDMywXQFRRBiTdLxsYEmRhc2hfYmFzZWxpbmVfMV92MREAdewHAA%3D%3D&_nc_rid=4c0a442ffe&ccb=7-4&oe=618EC549&oh=e856e793ad203a3c7ea8ed6cac3d5775&_nc_sid=6136e7 +/Users/shixuesen/OneDrive/Pictures/instagram/ngoctrinh89/ https://scontent-lax3-2.cdninstagram.com/v/t50.12441-16/254758393_231729622398943_1866383725571819196_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5zdG9yeS5iYXNlbGluZSJ9&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=107&_nc_ohc=JKjNtVofEp4AX-Avfsy&edm=AOVtZ6oBAAAA&vs=923366971946605_873367836&_nc_vs=HBksFQAYJEdQbE5Mdy1mdDlQQndkSUFBTHhHUnlFY3V1WVpicGt3QUFBRhUAAsgBABUAGCRHRThKTkE4YUtYSTNBMU1EQVBVTTR4aWVBZUZVYnBrd0FBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMRUAACa%2BpbDsvLjnPxUCKAJDMywXQCnul41P3zsYEmRhc2hfYmFzZWxpbmVfMV92MREAdegHAA%3D%3D&_nc_rid=db416de36b&ccb=7-4&oe=618E9055&oh=c04dd0684110bba1ac2578d052d32be9&_nc_sid=bab638 +/Users/shixuesen/OneDrive/Pictures/instagram/amandacerny/ https://scontent-lax3-2.cdninstagram.com/v/t50.16885-16/10000000_4629376703793775_2334129745422247097_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5pZ3R2LmRlZmF1bHQifQ&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=107&_nc_ohc=LUBoeTBtfssAX-BcK3q&edm=ABmJApABAAAA&vs=17919407948022979_1863409924&_nc_vs=HBksFQAYJEdJQ1dtQUJ2Q3ZiQlpISVFBTG5ra1BfaWZtUWdidlZCQUFBRhUAAsgBABUAGCRHQzh1V0E4clBjTkI1WGNFQUp6MFdDY3luVkI5YnZWQkFBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMRUAACbMtO%2BSjKjPPxUCKAJDMywXQGfMzMzMzM0YEmRhc2hfYmFzZWxpbmVfMV92MREAdewHAA%3D%3D&_nc_rid=3cbf47fb86&ccb=7-4&oe=61951857&oh=40cc117cf0f8208b010d71aa35c3c75a&_nc_sid=6136e7 +/Users/shixuesen/OneDrive/Pictures/instagram/bivi_0420/ https://scontent-lax3-1.cdninstagram.com/v/t50.16885-16/258170670_141009421609949_5774386139785023088_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5pZ3R2LmRlZmF1bHQifQ&_nc_ht=scontent-lax3-1.cdninstagram.com&_nc_cat=105&_nc_ohc=uprxKMAhYGQAX9WdIPX&edm=ABmJApABAAAA&vs=17906971082258721_2473403716&_nc_vs=HBksFQAYJEdDNWZZdy1kSzN4UVA0QUFBSEJPMDZHWnZTSlFidlZCQUFBRhUAAsgBABUAGCRHTE54VEEtSEdYVU05amdDQUk0WGpCZFpIQjVLYnZWQkFBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMRUAACbQzeuJ%2FLrKPxUCKAJDMywXQDyqfvnbItEYEmRhc2hfYmFzZWxpbmVfMl92MREAdewHAA%3D%3D&_nc_rid=53d9636037&ccb=7-4&oe=6196EB24&oh=f82cc96bb880dac903ff780ff7d97f8f&_nc_sid=6136e7 +/Users/shixuesen/OneDrive/Pictures/instagram/duyenn.hipp/ https://scontent-lax3-2.cdninstagram.com/v/t51.2885-15/e35/255960388_217661747141994_7464141834258348981_n.jpg?se=7&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=106&_nc_ohc=SuE7oWI6OR8AX9cu0il&edm=ABmJApABAAAA&ccb=7-4&oh=a6e4398099900110dce016eed2c349e6&oe=619ACE92&_nc_sid=6136e7&ig_cache_key=MjcwNzM3OTgxNjEzNDEyMDE5NQ%3D%3D.2-ccb7-4 +/Users/shixuesen/OneDrive/Pictures/instagram/amandacerny/ https://scontent-lax3-2.cdninstagram.com/v/t50.2886-16/10000000_316268253649051_7769614224832203038_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5jbGlwcy5iYXNlbGluZSJ9&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=107&_nc_ohc=Z0REJmgi8YkAX9E6YC7&edm=ABmJApABAAAA&vs=1081044149101308_373756612&_nc_vs=HBksFQAYJEdJQ1dtQUNibU9ud3BCOEJBQjRKOHVqNE50TnJicV9FQUFBRhUAAsgBABUAGCRHUHN2UlEtRFFpVzlTZ01IQUtaYWJTYUY3WDF0YnFfRUFBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMBUAACau1efT7cDZPxUCKAJDMywXQE37peNT988YEmRhc2hfYmFzZWxpbmVfMV92MREAdf4HAA%3D%3D&_nc_rid=baeafc3f78&ccb=7-4&oe=61984CF4&oh=e9ad8324785d5212e0e22ce46796160a&_nc_sid=6136e7 +/Users/shixuesen/OneDrive/Pictures/instagram/ngoctrinh89/ https://scontent-lax3-2.cdninstagram.com/v/t50.2886-16/10000000_477920383547067_7151630549725528088_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5jbGlwcy5iYXNlbGluZSJ9&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=103&_nc_ohc=tnecl6kzcX4AX8r6NGk&edm=ABmJApABAAAA&vs=434152981430001_3254225817&_nc_vs=HBksFQAYJEdJQ1dtQUM3TnJHQ3FySUJBQmpBT0JFWXNqOWpicV9FQUFBRhUAAsgBABUAGCRHSGlXYkE5aXM2TFg5MlVCQUQxQjEzd0dHODhiYnFfRUFBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMBUAACb8tt2L04HWPxUCKAJDMywXQE1u2RaHKwIYEmRhc2hfYmFzZWxpbmVfMV92MREAdf4HAA%3D%3D&_nc_rid=d819226fa1&ccb=7-4&oe=6199261E&oh=d6d0772349deb4e345d88321b3456df9&_nc_sid=6136e7 +/Users/shixuesen/OneDrive/Pictures/instagram/amandacerny/ https://scontent-lax3-2.cdninstagram.com/v/t50.2886-16/10000000_288901286576539_6067234896254624566_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5jbGlwcy5iYXNlbGluZSJ9&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=107&_nc_ohc=3q2O2VHcZu8AX-tA1xF&edm=ABmJApABAAAA&vs=215243547393407_2341694866&_nc_vs=HBksFQAYJEdJQ1dtQUNid1k4U3dRWUJBRFpqSEJqX0pUTlVicV9FQUFBRhUAAsgBABUAGCRHRUs0WmdfMXNCNVlPVzBFQUsteDdybF9ZY0IxYnFfRUFBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMBUAACaix5Ldj8CFQBUCKAJDMywXQD%2F3S8an754YEmRhc2hfYmFzZWxpbmVfMV92MREAdf4HAA%3D%3D&_nc_rid=887a455722&ccb=7-4&oe=619B174D&oh=0da8018e4e502a50b92809c122962b96&_nc_sid=6136e7 +/Users/shixuesen/OneDrive/Pictures/instagram/ngoctrinh89/ https://scontent-lax3-2.cdninstagram.com/v/t50.2886-16/10000000_313009227078783_3250413392895561598_n.mp4?efg=eyJ2ZW5jb2RlX3RhZyI6InZ0c192b2RfdXJsZ2VuLjcyMC5jbGlwcy5iYXNlbGluZSJ9&_nc_ht=scontent-lax3-2.cdninstagram.com&_nc_cat=103&_nc_ohc=uZYW0910QqgAX-wESJO&edm=ABmJApABAAAA&vs=203881368589343_1990162413&_nc_vs=HBksFQAYJEdJQ1dtQUItbk1vanJod0JBSDVQdG1qQ3lSc3RicV9FQUFBRhUAAsgBABUAGCRHRllxYWc4OExtUkhsam9CQUtQQ2lUcGJpYTFBYnFfRUFBQUYVAgLIAQAoABgAGwGIB3VzZV9vaWwBMBUAACbWsq7ZpuDnPxUCKAJDMywXQEFAAAAAAAAYEmRhc2hfYmFzZWxpbmVfMV92MREAdf4HAA%3D%3D&_nc_rid=794cd77827&ccb=7-4&oe=619D207A&oh=d4f2f04b6a759828b1c7ba8c2380e37c&_nc_sid=6136e7