Animarr/src/Animarr/Release/Release.php

837 lines
17 KiB
PHP
Executable file

<?php
namespace Animarr\Release;
use Animarr\Extractor\SceneExtractor;
use Animarr\Filter;
use Animarr\Torrent\Torrent;
use Animarr\Database;
class Release{
const TYPE_SINGLE = 0;
const TYPE_VOLUME = 1;
const TYPE_BATCH = 2;
const TYPE_SPECIAL = 3;
const SPECIAL_TYPE_UNKNOWN = -1;
const SPECIAL_TYPE_OVA = 0;
const SPECIAL_TYPE_MOVIE = 1;
const SPECIAL_TYPE_OP = 2;
const SPECIAL_TYPE_ED = 3;
const SPECIAL_TYPE_NCOP = self::SPECIAL_TYPE_OP;
const SPECIAL_TYPE_NCED = self::SPECIAL_TYPE_ED;
const SPECIAL_TYPE_PV = 4;
const SPECIAL_TYPE_CM = 5;
const SPECIAL_TYPE_SP = self::SPECIAL_TYPE_OVA;
#const SPECIAL_TYPE_S = self::SPECIAL_TYPE_OVA;
const QUALITY_UNKNOWN = -1;
const QUALITY_480 = 480;
const QUALITY_576 = 576;
const QUALITY_720 = 720;
const QUALITY_1080 = 1080;
const SOURCE_UNKNOWN = -1;
const SOURCE_WEB = 1;
const SOURCE_TV = 2;
const SOURCE_DVD = 3;
const SOURCE_BLURAY = 4;
const SOURCE_LASERDISC = 5;
const VIDEO_CODEC_UNKNOWN = -1;
const VIDEO_CODEC_H264_10 = 1;
const VIDEO_CODEC_H264 = 2;
const VIDEO_CODEC_HEVC = 3;
const VIDEO_CODEC_MPEG4 = 4;
const AUDIO_CODEC_UNKNOWN = -1;
const AUDIO_CODEC_FLAC = 1;
const AUDIO_CODEC_AAC = 2;
const AUDIO_CODEC_AC3 = 3;
const AUDIO_CODEC_DTS = 3;
protected $content = null;
private $originalTitle;
private $title;
private $type;
private $specialType;
private $group;
private $tags = [];
private $number;
private $properties = [];
private $quality;
private $source;
private $audioCodec;
private $videoCodec;
private $infoLink;
private $downloadLink;
private $uploadDate;
private $seeds = -1;
private $size;
private $trusted = false;
private $best = false;
private $CRC = null;
private $version = 1;
/** @var Filter */
protected $filter = null;
/**
* @return Release[]
*/
public function getContents(SceneExtractor $extractor = null){
if($this->content !== null){
return $this->content;
}
$this->content = [];
$extractor = $extractor === null ? new SceneExtractor() : $extractor;
$torrent = Torrent::fromURL($this->getDownloadLink(), Database::getConfigKey("torrent.cache.folder", null));
if($torrent === null and strpos($this->getDownloadLink(), "urn:btih:") !== false){
//Support magnets
$this->content[$this->getNumber()] = $this;
return $this->content;
}
foreach ($torrent->getFiles() as $file){
if(count($file["path"]) > 1){ //In subfolder, let's ignore for now
continue;
}
$baseName = $file["path"][count($file["path"]) - 1];
$release = $extractor->extractInformation($baseName);
if($release === null or $release->getType() !== Release::TYPE_SINGLE){
continue;
}
$release->setInfoLink($this->getInfoLink());
$release->setDownloadLink($this->getDownloadLink());
$release->setUploadDate($this->getUploadDate());
$release->setTrusted($this->isTrusted());
$release->setBest($this->isBest());
$release->setSeeds($this->getSeeds());
$release->setSize($this->getSize());
$release->setParent($this);
if($release->getSource() === Release::SOURCE_UNKNOWN){
$release->setSource($this->getSource());
}
if($release->getQuality() === Release::QUALITY_UNKNOWN){
$release->setQuality($this->getQuality());
}
if($release->getVideoCodec() === Release::VIDEO_CODEC_UNKNOWN){
$release->setVideoCodec($this->getVideoCodec());
}
if($release->getAudioCodec() === Release::AUDIO_CODEC_UNKNOWN){
$release->setAudioCodec($this->getAudioCodec());
}
$release->setProperties($this->getProperties());
if($this->filter !== null){
$release = $this->filter->applyFilterSingle($release);
}
if($release === null){
continue;
}
$this->content[$release->getNumber()] = $release;
}
ksort($this->content);
return $this->content;
}
public function setProperty($k, $v){
$this->properties[$k] = $v;
}
public function getProperty($k, $default = null){
return isset($this->properties[$k]) ? $this->properties[$k] : $default;
}
public function setProperties($props){
return $this->properties = $props;
}
public function getProperties(){
return $this->properties;
}
public function setFilter(Filter $filter = null){
if($filter !== $this->filter){
$this->content = null;
}
$this->filter = $filter;
}
/**
* @return string
*/
public function getCRC(){
return $this->CRC;
}
/** @var Release */
private $parent = null;
/**
* @return Release|null
*/
public function getParent(){
return $this->parent;
}
/**
* @param Release $parent
*/
public function setParent(Release $parent){
$this->parent = $parent;
$this->setFilter($parent->filter);
}
/**
* @return boolean
*/
public function isBest(): bool{
return $this->best;
}
/**
* @param boolean $best
*/
public function setBest(bool $best){
$this->best = $best;
}
/**
* @return boolean
*/
public function isTrusted(): bool{
return $this->trusted;
}
/**
* @param boolean $trusted
*/
public function setTrusted(bool $trusted){
$this->trusted = $trusted;
}
/**
* @return mixed
*/
public function getVersion(){
return $this->version;
}
/**
* @param mixed $version
*/
public function setVersion($version){
$this->version = $version;
}
/**
* @return mixed
*/
public function getInfoLink(){
return $this->infoLink;
}
/**
* @param mixed $infoLink
*/
public function setInfoLink($infoLink){
$this->infoLink = html_entity_decode($infoLink);
}
/**
* @return mixed
*/
public function getAudioCodec(){
return $this->audioCodec;
}
/**
* @param mixed $audioCodec
*/
public function setAudioCodec($audioCodec){
$this->audioCodec = $audioCodec;
}
/**
* @return mixed
*/
public function getVideoCodec(){
return $this->videoCodec;
}
/**
* @param mixed $videoCodec
*/
public function setVideoCodec($videoCodec){
$this->videoCodec = $videoCodec;
}
/**
* @return mixed
*/
public function getDownloadLink(){
return $this->downloadLink;
}
/**
* @param mixed $downloadLink
*/
public function setDownloadLink($downloadLink){
$this->downloadLink = html_entity_decode($downloadLink);
}
/**
* @return mixed
*/
public function getUploadDate(){
return $this->uploadDate;
}
/**
* @param mixed $uploadDate
*/
public function setUploadDate($uploadDate){
$this->uploadDate = $uploadDate;
}
/**
* @return mixed
*/
public function getSeeds(){
return $this->seeds;
}
/**
* @param mixed $seeds
*/
public function setSeeds($seeds){
$this->seeds = $seeds;
}
/**
* @return mixed
*/
public function getSize(){
return $this->size;
}
/**
* @param mixed $size
*/
public function setSize($size){
$this->size = $size;
}
/**
* @return string
*/
public function getTitle(){
return $this->title;
}
/**
* @return string
*/
public function getOriginalTitle(){
return $this->originalTitle;
}
/**
* @param string $title
*/
public function setTitle($title){
$this->title = $title;
}
/**
* @return int
*/
public function getType(){
return (int) $this->type;
}
/**
* @param int $type
*/
public function setType($type){
$this->type = $type;
}
public function getSpecialType(){
if($this->specialType === null){
$this->guessSpecialType();
}
return (int) $this->specialType;
}
/**
* @param int $type
*/
public function setSpecialType($type){
$this->specialType = $type;
}
/**
* @return mixed
*/
public function getGroup(){
return $this->group;
}
public function getSourceString(){
switch($this->getSource()){
case self::SOURCE_LASERDISC:
return "LD";
case self::SOURCE_BLURAY:
return "BLURAY";
case self::SOURCE_DVD:
return "DVD";
case self::SOURCE_TV:
return "TV";
case self::SOURCE_WEB:
return "WEB";
}
return "UNKNOWN";
}
public function getTypeString(){
switch($this->getType()){
case self::TYPE_SINGLE:
return "SINGLE";
case self::TYPE_VOLUME:
return "VOLUME";
case self::TYPE_BATCH:
return "BATCH";
case self::TYPE_SPECIAL:
return "SPECIAL";
}
return "UNKNOWN";
}
public function getQualityString(){
return $this->getQuality() > 0 ? $this->getQuality() . "p" : "UNKNOWN";
}
/**
* @param mixed $group
*/
public function setGroup($group){
$this->group = $group;
}
/**
* @return string[]
*/
public function getTags(): array{
return $this->tags;
}
/**
* @param string[] $tags
*/
public function setTags(array $tags){
$this->tags = $tags;
}
/**
* @return int
*/
public function getNumber(): int{
return $this->number;
}
public function getId(){
return sha1($this->getDownloadLink());
}
/**
* @param int $number
*/
public function setNumber(int $number){
$this->number = $number;
}
/**
* @return int
*/
public function getQuality(){
return $this->quality;
}
/**
* @param int $quality
*/
public function setQuality($quality){
$this->quality = $quality;
}
/**
* @return int
*/
public function getSource(){
return $this->source;
}
/**
* @param int $source
*/
public function setSource($source){
$this->source = $source;
}
public function __construct($originalTitle, $title, $group, $type, array $tags, $number = -1){
$this->originalTitle = $originalTitle;
$this->title = $title;
$this->group = $group;
$this->type = $type;
$this->tags = $tags;
$this->number = $number;
$this->uploadDate = time();
$this->guessSource();
$this->guessQuality();
$this->guessAudioCodec();
$this->guessVideoCodec();
$this->guessCRC();
}
private function guessQuality(){
$this->quality = self::QUALITY_UNKNOWN;
foreach($this->tags as $t){
$quality = self::QUALITY_UNKNOWN;
switch(strtolower($t)){
case "1080p":
case "1920x1080":
case "1440x1080": //4:3
case "900p":
case "810p":
case "bd1080p":
$quality = self::QUALITY_1080;
break;
case "700p":
case "720p":
case "1280x720":
case "1024x768": //4:3, strange res
case "1280x960": //4:3, strange res
case "768p": //wat https://www.nyaa.se/?page=view&tid=845988
case "bd720p":
case "hdtv":
$quality = self::QUALITY_720;
break;
case "576p":
case "1024x576":
case "768x576":
case "1024x576p":
case "768x576p":
$quality = self::QUALITY_576;
break;
case "640x480":
case "848x480":
case "852x480":
case "720x480":
case "720x540":
case "640x480p":
case "848x480p":
case "852x480p":
case "720x480p":
case "720x540p":
case "480p":
$quality = self::QUALITY_480;
break;
}
if($quality > $this->quality){
$this->quality = $quality;
}
}
if($this->quality === self::QUALITY_UNKNOWN){
$quality = self::QUALITY_UNKNOWN;
if($this->getSource() === self::SOURCE_DVD){
$quality = self::QUALITY_576;
}else if($this->getSource() === self::SOURCE_BLURAY){
$quality = self::QUALITY_720;
}if($this->getSource() === self::SOURCE_TV){
$quality = self::QUALITY_720;
}
if($quality > $this->quality){
$this->quality = $quality;
}
}
}
private function guessSpecialType(){
$this->specialType = Release::SPECIAL_TYPE_UNKNOWN;;
foreach(preg_split("/[\\.\s,\\-\\[\\]\\(\\)]+/", $this->originalTitle) as $t){
$source = self::SOURCE_UNKNOWN;
$typeConstant = Release::class . "::SPECIAL_TYPE_" . strtoupper($t);
if(defined($typeConstant)){
$this->specialType = $typeConstant;
break;
}
}
}
private function guessSource(){
$this->source = self::SOURCE_UNKNOWN;
foreach($this->tags as $t){
$source = self::SOURCE_UNKNOWN;
switch(strtolower($t)){
case "bd":
case "bdmux":
case "bdremux":
case "blu":
case "bluray":
case "bdrip":
case "brrip":
case "bd720p":
case "bd1080p":
$source = self::SOURCE_BLURAY;
break;
case "hdtv":
case "tv":
$source = self::SOURCE_TV;
break;
case "cr":
case "web":
case "webrip":
case "webdl":
case "odrip": //On-Demand rip
case "dl":
case "funidl":
$source = self::SOURCE_WEB;
break;
case "ld":
case "ldrip":
case "laserdisc":
$source = self::SOURCE_LASERDISC;
break;
case "dvd":
case "dvdrip":
$source = self::SOURCE_DVD;
break;
}
if($source > $this->source){
$this->source = $source;
}
}
}
private function guessAudioCodec(){
$this->audioCodec = self::AUDIO_CODEC_UNKNOWN;
foreach($this->tags as $t){
$audioCodec = self::AUDIO_CODEC_UNKNOWN;
switch(strtolower($t)){
case "ac":
case "ac3":
case "dd":
case "truehd":
$audioCodec = self::AUDIO_CODEC_AC3;
break;
case "dts":
$audioCodec = self::AUDIO_CODEC_DTS;
break;
case "flac":
case "flac2":
case "flac3":
case "flac5":
case "flacx2":
case "flacx3":
case "flacx5":
$audioCodec = self::AUDIO_CODEC_FLAC;
break;
case "aac":
case "aac2":
case "aac5":
$audioCodec = self::AUDIO_CODEC_AAC;
break;
}
if($audioCodec > $this->audioCodec){
$this->audioCodec = $audioCodec;
}
}
}
private function guessVideoCodec(){
$this->videoCodec = self::VIDEO_CODEC_UNKNOWN;
foreach($this->tags as $t){
$videoCodec = self::VIDEO_CODEC_UNKNOWN;
switch(strtolower($t)){
case "265":
case "h265":
case "x265":
case "hevc":
case "hevc2":
$videoCodec = self::VIDEO_CODEC_HEVC;
break;
case "264":
case "h264":
case "x264":
case "8bit":
$videoCodec = self::VIDEO_CODEC_H264;
break;
case "10":
case "10bit":
case "10-bit":
case "hi10":
case "hi10p":
case "hi444p":
case "hi444pp":
$videoCodec = self::VIDEO_CODEC_H264_10;
break;
case "divx":
case "xvid":
case "mpeg4":
$videoCodec = self::VIDEO_CODEC_MPEG4;
break;
}
if($videoCodec > $this->videoCodec){
$this->videoCodec = $videoCodec;
}
}
}
private function guessCRC(){
$this->CRC = null;
foreach($this->tags as $t){
if(strlen($t) === 8 and preg_match("/[A-F0-9]{8}/", strtoupper($t)) > 0){
$this->CRC = strtoupper($t);
break;
}
}
}
public function serialize(){
return [
"id" => $this->getId(),
"name" => $this->getOriginalTitle(),
"title" => $this->getTitle(),
"number" => $this->getNumber(),
"group" => $this->getGroup(),
"type" => $this->getType(),
"source" => $this->getSource(),
"quality" => $this->getQuality(),
"version" => $this->getVersion(),
"properties" => $this->getProperties(),
"tags" => array_values($this->getTags()),
"trusted" => $this->isTrusted(),
"best" => $this->isBest(),
"seeds" => $this->getSeeds(),
"infoLink" => $this->getInfoLink(),
"specialType" => $this->getSpecialType(),
"downloadLink" => $this->getDownloadLink(),
"size" => $this->getSize(),
"uploadDate" => $this->getUploadDate(),
"parent" => $this->getParent() !== null ? $this->getParent()->serialize() : null
];
}
public function encode(){
return json_encode($this->serialize());
}
public static function undecode($data){
return Release::unserialize(json_decode($data, true));
}
public static function unserialize(array $data){
/** @var Release $release */
$release = null;
switch ($data["type"]){
case Release::TYPE_SINGLE:
$release = new Release($data["name"], $data["title"], $data["group"], $data["type"], $data["tags"], $data["number"]);
break;
case Release::TYPE_SPECIAL:
$release = new Release($data["name"], $data["title"], $data["group"], $data["type"], $data["tags"], $data["number"]);
break;
case Release::TYPE_VOLUME:
$release = new MultiRelease($data["name"], $data["title"], $data["group"], $data["type"], $data["tags"], $data["number"]);
break;
case Release::TYPE_BATCH:
$release = new MultiRelease($data["name"], $data["title"], $data["group"], $data["type"], $data["tags"], $data["number"]);
break;
}
if($release !== null){
$release->setSource($data["source"]);
$release->setQuality($data["quality"]);
$release->setTrusted($data["trusted"]);
$release->setBest($data["best"]);
$release->setSeeds($data["seeds"]);
$release->setInfoLink($data["infoLink"]);
$release->setDownloadLink($data["downloadLink"]);
$release->setSize($data["size"]);
$release->setUploadDate($data["uploadDate"]);
if(isset($data["properties"])){
$release->setProperties($data["properties"]);
}
if(isset($data["specialType"])){
$release->setSpecialType($data["specialType"]);
}
if($data["parent"] !== null){
$release->setParent(Release::unserialize($data["parent"]));
}
}
return $release;
}
}