2021-11-21 03:17:10 +00:00
// ==UserScript==
// @name AnimeBytes Mediainfo Improvements
// @author WeebDataHoarder
2021-11-29 18:10:20 +00:00
// @version 1.13.1
2021-11-21 03:17:10 +00:00
// @downloadURL https://git.gammaspectra.live/WeebDataHoarder/userscripts/raw/branch/master/AnimeBytes/ab-mediainfo.user.js
// @updateURL https://git.gammaspectra.live/WeebDataHoarder/userscripts/raw/branch/master/AnimeBytes/ab-mediainfo.user.js
// @description AnimeBytes Mediainfo Improvements. Adds several listing and matching releases against mediainfo utilities. MIT license
// @match https://animebytes.tv/torrents.php?*id=*
2021-11-29 18:02:16 +00:00
// @match https://animebytes.tv/user.php?action=edit
2021-11-25 21:12:43 +00:00
// @icon https://mei.animebytes.tv/jEBHMictkaa.png
2021-11-25 18:53:41 +00:00
// @grant GM_addStyle
2021-11-29 18:02:16 +00:00
// @grant GM_setValue
// @grant GM_getValue
2021-11-21 03:17:10 +00:00
// @run-at document-end
// ==/UserScript==
2021-11-25 19:16:58 +00:00
if ( typeof GM _addStyle !== 'function' ) {
window . GM _addStyle = ( css ) => {
const style = document . getElementById ( "GM_addStyle" ) || ( ( ) => {
const style = document . createElement ( 'style' ) ;
style . type = 'text/css' ;
style . id = "GM_addStyle" ;
document . head . appendChild ( style ) ;
return style ;
} ) ( ) ;
const sheet = style . sheet ;
sheet . insertRule ( css , ( sheet . rules || sheet . cssRules || [ ] ) . length ) ;
}
}
2021-11-29 18:10:20 +00:00
if ( typeof GM _getValue !== 'function' ) {
window . GM _getValue = ( name , defaultValue ) => {
let v = window . localStorage . getItem ( "__mediainfo_userscript_" + name ) ;
return v !== null ? JSON . parse ( v ) : defaultValue ;
}
}
if ( typeof GM _setValue !== 'function' ) {
window . GM _setValue = ( name , value ) => {
window . localStorage . setItem ( "__mediainfo_userscript_" + name , JSON . stringify ( value ) ) ;
}
}
2021-11-21 03:17:10 +00:00
function parseMediaInfo ( text ) {
let ob = { } ;
let currentKey = null ;
let currentOb = null ;
try {
text . split ( "\n" ) . forEach ( ( line ) => {
const cleanLine = line . trim ( ) ;
if ( cleanLine === "" ) {
return ;
} else if ( ! cleanLine . includes ( ":" ) ) {
if ( currentOb !== null && Object . keys ( currentOb ) . length === 0 ) {
//Nothing added, error, invalid mediainfo
throw ( "Invalid key " + currentKey ) ;
}
2021-11-29 15:19:31 +00:00
if ( currentKey === null && cleanLine . toLowerCase ( ) !== "general" ) {
throw ( "Invalid first key " + cleanLine . toLowerCase ( ) ) ;
}
2021-11-21 03:17:10 +00:00
currentKey = cleanLine . toLowerCase ( ) ;
let listMatch = currentKey . match ( /^(?<kind>(video|audio|text))( #)?(?<number>[0-9]*)$/i ) ;
currentOb = { } ;
if ( listMatch !== null ) {
let k = listMatch . groups . kind ;
if ( ! ( k in ob ) ) {
ob [ k ] = [ ] ;
}
ob [ k ] . push ( currentOb ) ;
} else {
ob [ currentKey ] = currentOb ;
}
} else if ( currentOb !== null ) {
2021-11-26 09:42:15 +00:00
const matches = currentKey === "menu" ? cleanLine . match ( /^(?<key>([0-9]+:)+[0-9]+(\.[0-9]+)?)[\s]*:(?<value>.+)$/ ) : cleanLine . match ( /^(?<key>((?!\s?:).)+)[\s]*:(?<value>.+)$/ ) ;
2021-11-21 03:17:10 +00:00
if ( matches !== null ) {
2021-11-21 14:41:03 +00:00
let key = matches . groups . key . trim ( ) . toLowerCase ( ) . replace ( /[ \/*]/g , "_" ) . replace ( /[(),]/g , "" ) ;
2021-11-21 03:17:10 +00:00
currentOb [ key ] = matches . groups . value . trim ( ) ;
} else {
2021-11-25 17:36:14 +00:00
throw "Invalid entry: " + cleanLine ;
2021-11-21 03:17:10 +00:00
}
} else {
2021-11-25 17:36:14 +00:00
throw "Invalid state: " + cleanLine ;
2021-11-21 03:17:10 +00:00
}
} ) ;
} catch ( e ) {
console . log ( text ) ;
console . log ( e ) ;
2021-11-25 19:53:01 +00:00
if ( "general" in ob && "video" in ob ) { //Return whatever we have
return ob ;
}
2021-11-21 03:17:10 +00:00
return null ;
}
return ob ;
}
2021-11-25 18:07:42 +00:00
/ * *
* @ param v
* @ param legacy
* @ returns String
* /
2021-11-21 03:17:10 +00:00
function getLineTagEntry ( v , legacy ) {
if ( typeof v === 'object' ) {
return legacy ? v . legacy : ( v . name /* + ("lossless" in v ? " (Lossless)" : "")*/ ) ;
}
return v ;
}
function getAudioChannels ( a ) {
if ( a === 3 ) {
return "2.1" ;
} else if ( a === 5 ) {
return "4.1" ;
} else if ( a === 6 ) {
return "5.1" ;
} else if ( a === 8 ) {
return "7.1" ;
}
return a + ".0" ;
}
function getComparisonLine ( tags ) {
let entries = [ ] ;
entries . push ( getLineTagEntry ( tags . source , true ) ) ;
entries . push ( getLineTagEntry ( tags . container , true ) + ( "region" in tags ? " (" + tags . region + ")" : "" ) ) ;
if ( "aspectRatio" in tags ) {
entries . push ( tags . aspectRatio ) ;
}
2021-11-25 18:07:42 +00:00
if ( "videoCodec" in tags && ! (
getLineTagEntry ( tags . source , true ) . match ( /^DVD[59]$/ ) !== null
) ) {
2021-11-21 03:17:10 +00:00
entries . push ( getLineTagEntry ( tags . videoCodec , true ) ) ;
}
entries . push ( tags . resolution ) ;
entries . push ( getLineTagEntry ( tags . audioCodec , true ) + " " + getAudioChannels ( tags . audioChannels ) ) ;
if ( tags . audioCount > 1 ) {
entries . push ( "Dual Audio" ) ;
}
entries . push ( ( "subtitleType" in tags ? getLineTagEntry ( tags . subtitleType , true ) : "RAW" ) + ( "group" in tags ? " (" + tags . group + ")" : "" ) ) ;
return entries . join ( " | " ) ;
}
2021-11-25 18:07:42 +00:00
function getEntryLine ( tags , infoCount , warningCount , dangerCount ) {
// Source + container + remux | Codec / Resolution / HDR | Audio + Dual + commentary | Text | OtherTags | icons
let entries = {
source : [ ] ,
video : [ ] ,
audio : [ ] ,
text : [ ] ,
other : [ ] ,
icons : [ ]
} ;
entries . source . push ( getLineTagEntry ( tags . source , false ) + ( "sourceName" in tags ? " (" + tags . sourceName + ")" : "" ) ) ;
entries . source . push ( getLineTagEntry ( tags . container , false ) + ( "region" in tags ? " (" + tags . region + ")" : "" ) ) ;
entries . video . push ( getLineTagEntry ( tags . videoCodec , false ) + ( "videoEncoder" in tags ? " (" + tags . videoEncoder + ( "videoCRF" in tags ? " " + tags . videoCRF : "" ) + ")" : "" ) ) ;
entries . video . push ( tags . resolution + ( "aspectRatio" in tags ? " " + tags . aspectRatio : "" ) /* + ("videoFrameRate" in tags ? " @ " + tags.videoFrameRate : "")*/ ) ;
2021-11-21 03:17:10 +00:00
if ( "videoHDR" in tags ) {
2021-11-25 18:07:42 +00:00
entries . video . push ( getLineTagEntry ( tags . videoHDR , false ) ) ;
2021-11-21 03:17:10 +00:00
}
2021-11-26 09:28:35 +00:00
if ( tags . videoCount > 1 ) {
entries . video . push ( tags . videoCount === 2 ? "Dual" : "Multi (" + tags . videoCount + ")" ) ;
}
2021-11-21 03:17:10 +00:00
2021-11-25 18:07:42 +00:00
entries . audio . push ( getLineTagEntry ( tags . audioCodec , false ) + " " + getAudioChannels ( tags . audioChannels ) ) ;
2021-11-21 03:17:10 +00:00
if ( tags . audioCount > 1 ) {
2021-11-25 19:53:01 +00:00
entries . audio . push ( tags . audioCount === 2 ? "Dual" : "Multi (" + tags . audioCount + ")" ) ;
2021-11-21 03:17:10 +00:00
}
2021-11-21 13:15:27 +00:00
if ( "audioCommentary" in tags && tags . audioCommentary ) {
2021-11-25 18:07:42 +00:00
entries . audio . push ( "Commentary" ) ;
2021-11-21 13:15:27 +00:00
}
2021-11-21 14:41:03 +00:00
if ( "remux" in tags ) {
if ( tags . remux === true ) {
2021-11-25 18:07:42 +00:00
entries . source . push ( "REMUX" ) ;
2021-11-21 14:41:03 +00:00
} else if ( tags . remux === "probably" ) {
2021-11-25 18:07:42 +00:00
entries . source . push ( "REMUX*" ) ;
2021-11-21 14:41:03 +00:00
}
}
2021-11-21 13:15:27 +00:00
if ( tags . remastered ) {
let img = document . createElement ( "img" ) ;
img . src = "/static/common/rmstr.png" ;
img . alt = "Remastered" ;
img . title = "This torrent is from a remastered source!" ;
2021-11-25 18:07:42 +00:00
entries . other . push ( img ) ;
2021-11-21 13:15:27 +00:00
}
2021-11-25 18:07:42 +00:00
entries . text . push ( ( "subtitleCodec" in tags ? tags . subtitleCodec + " " : "" ) + ( "subtitleType" in tags ? getLineTagEntry ( tags . subtitleType , false ) : "RAW" ) + ( "group" in tags ? " (" + tags . group + ")" : "" ) ) ;
2021-11-21 03:17:10 +00:00
2021-11-21 13:15:27 +00:00
if ( tags . freeleech ) {
let img = document . createElement ( "img" ) ;
img . src = "/static/common/flicon.png" ;
img . alt = "Freeleech!" ;
img . title = "This torrent is freeleech. Remember to seed!" ;
2021-11-25 18:07:42 +00:00
entries . other . push ( img ) ;
}
if ( "chapters" in tags ) {
entries . other . push ( tags . chapters === "ordered" ? "Ordered Chapters" : "Chapters" ) ;
}
if ( tags . snatched ) {
entries . other . push ( "Snatched" ) ;
2021-11-21 13:15:27 +00:00
}
2021-11-25 18:07:42 +00:00
if ( infoCount > 0 || warningCount > 0 || dangerCount > 0 ) {
let span = document . createElement ( "span" ) ;
for ( let i = 0 ; i < infoCount ; ++ i ) {
span . append ( "★" ) ;
}
for ( let i = 0 ; i < warningCount ; ++ i ) {
let icon = document . createElement ( "img" ) ;
icon . src = "/static/common/symbols/warned.png" ;
span . append ( icon ) ;
}
for ( let i = 0 ; i < dangerCount ; ++ i ) {
let icon = document . createElement ( "img" ) ;
icon . src = "/static/common/symbols/disabled.png" ;
span . append ( icon ) ;
}
entries . icons . unshift ( span ) ;
}
2021-11-21 13:15:27 +00:00
return entries ;
2021-11-21 03:17:10 +00:00
}
const allowedVideoTypes = [
"Movie" ,
"OVA" ,
"ONA" ,
"TV Series" ,
"TV Special" ,
"DVD Special" ,
"BD Special"
] ;
const knownSources = [
"TV" ,
"DVD" ,
"DVD5" ,
"DVD9" ,
"Blu-ray" ,
"UHD Blu-ray" ,
"HD DVD" ,
"VHS" ,
"LD" ,
"Web"
] ;
const knownContainers = [
"AVI" ,
"MKV" ,
"MP4" ,
"OGM" ,
"WMV" ,
"MPG" ,
"ISO" ,
"VOB" ,
"VOB IFO" ,
"TS" ,
"M2TS" ,
"FLV" ,
"RMVB"
] ;
const knownVideoCodecs = [
"h264" ,
"h264 10-bit" ,
"h265" ,
"h265 10-bit" ,
"XviD" ,
"DivX" ,
"WMV" ,
"MPEG-1/2" ,
"VC-1" ,
"MPEG-TS" ,
"DVD5" ,
"DVD9" ,
"RealVideo" ,
"VP6" ,
"VP9" ,
"AV1"
] ;
const knownAudioCodecs = [
"MP3" ,
"Vorbis" ,
"Opus" ,
"AAC" ,
"AC3" ,
"TrueHD" ,
"DTS" ,
"DTS-ES" ,
"FLAC" ,
"PCM" ,
"WMA" ,
"MP2" ,
"WAV" ,
"DTS-HD" ,
"DTS-HD MA" ,
"RealAudio"
] ;
const audioCodecs = [
2021-11-21 17:35:27 +00:00
{
name : "AAC-LC" ,
match : {
codec _id : /^A_AAC/ ,
format _profile : "LC"
} ,
legacy : "AAC"
} ,
2021-11-22 09:10:25 +00:00
{
name : "HE-AAC" ,
match : {
codec _id : /^A_AAC/ ,
format _profile : /HE-AAC/
} ,
2021-11-26 09:42:15 +00:00
legacy : "AAC"
2021-11-25 22:32:46 +00:00
} ,
{
name : "HE-AAC" ,
match : {
codec _id : "mp4a-40-5"
} ,
2021-11-22 09:10:25 +00:00
legacy : "AAC"
} ,
2021-11-21 17:35:27 +00:00
{
name : "AAC-LC" ,
match : {
2021-11-25 22:32:46 +00:00
codec _id : /^(A_AAC-2|mp4a-40-2)$/
2021-11-21 17:35:27 +00:00
} ,
legacy : "AAC"
} ,
{
name : "AAC-Main" ,
match : {
codec _id : "A_AAC-1"
} ,
legacy : "AAC"
} ,
{
name : "AAC-Main" ,
match : {
codec _id : "A_AAC" ,
format _profile : "Main"
} ,
legacy : "AAC"
} ,
{
name : "AC3" ,
match : {
codec _id : "A_AC3"
} ,
legacy : "AC3"
} ,
{
name : "Opus" ,
match : {
2021-11-25 22:32:46 +00:00
codec _id : /^(A_OPUS|opus)/
2021-11-21 17:35:27 +00:00
} ,
legacy : "Opus"
} ,
{
name : "Vorbis" ,
match : {
codec _id : "A_VORBIS"
} ,
legacy : "Vorbis"
} ,
{
name : "MP2" ,
match : {
codec _id : "A_MPEG/L2"
} ,
legacy : "MP2"
} ,
{
name : "MP3" ,
match : {
codec _id : "A_MPEG/L3"
} ,
legacy : "MP3"
} ,
2021-11-29 16:42:55 +00:00
{
name : "WAV" ,
match : {
codec _id : "A_WAVPACK4"
} ,
legacy : "WAV" ,
lossless : true ,
} ,
2021-11-21 17:35:27 +00:00
{
name : "FLAC" ,
match : {
codec _id : "A_FLAC"
} ,
legacy : "FLAC" ,
lossless : true
} ,
{
name : "PCM" ,
match : {
codec _id : "A_PCM/INT/LIT"
} ,
legacy : "PCM" ,
lossless : true
} ,
2021-11-21 03:17:10 +00:00
{
name : "E-AC3" ,
match : {
codec _id : "A_EAC3" ,
number _of _dynamic _objects : null
} ,
legacy : "AC3"
} ,
{
name : "E-AC3 Atmos" ,
match : {
codec _id : "A_EAC3" ,
number _of _dynamic _objects : /^[0-9]+$/
} ,
legacy : "AC3"
} ,
{
name : "TrueHD Atmos" ,
match : {
codec _id : "A_TRUEHD" ,
number _of _dynamic _objects : /^[0-9]+$/
} ,
legacy : "TrueHD" ,
lossless : true
} ,
2021-11-21 17:35:27 +00:00
{
name : "TrueHD" ,
match : {
codec _id : "A_TRUEHD" ,
number _of _dynamic _objects : null
} ,
legacy : "TrueHD" ,
lossless : true
} ,
2021-11-21 13:15:27 +00:00
2021-11-21 03:17:10 +00:00
{
name : "DTS:X MA" ,
match : {
codec _id : "A_DTS" ,
format : "DTS XLL X" ,
channels _original : "Object Based"
} ,
legacy : "DTS-HD MA" ,
lossless : true
} ,
{
name : "DTS-HD MA" ,
match : {
codec _id : "A_DTS" ,
format : "DTS XLL" ,
channels _original : null ,
} ,
legacy : "DTS-HD MA" ,
lossless : true
2021-11-21 13:15:27 +00:00
} ,
2021-11-21 17:35:27 +00:00
{
name : "DTS-HD" ,
match : {
codec _id : "A_DTS" ,
format : "DTS XBR" ,
} ,
legacy : "DTS-HD"
} ,
{
name : "DTS" ,
match : {
codec _id : "A_DTS" ,
format : "DTS" ,
format _profile : null ,
} ,
legacy : "DTS"
} ,
{
name : "DTS-ES" ,
match : {
codec _id : "A_DTS" ,
format : "DTS ES" ,
} ,
legacy : "DTS-ES"
} ,
{
name : "DTS-HD MA" ,
match : {
codec _id : "A_DTS" ,
format _profile : /^MA/ ,
channels _original : null ,
} ,
legacy : "DTS-HD MA" ,
lossless : true
} ,
{ //Old way of identifying
name : "DTS-ES" ,
match : {
codec _id : "A_DTS" ,
format _profile : /^ES/ ,
} ,
legacy : "DTS-ES"
} ,
2021-11-21 13:15:27 +00:00
{ //Old way of identifying
name : "DTS-HD MA" ,
match : {
codec _id : "A_DTS" ,
format _profile : "MA / Core" ,
channels _original : null ,
} ,
legacy : "DTS-HD MA" ,
lossless : true
2021-11-21 03:17:10 +00:00
}
] ;
const videoCodecs = [
2021-11-22 09:10:25 +00:00
2021-11-21 03:17:10 +00:00
{
2021-11-22 09:10:25 +00:00
name : "MPEG-1" ,
2021-11-21 03:17:10 +00:00
match : {
2021-11-22 09:10:25 +00:00
codec _id : "V_MPEG1" ,
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
legacy : "MPEG-1/2"
2021-11-21 03:17:10 +00:00
} ,
{
2021-11-22 09:10:25 +00:00
name : "MPEG-2" ,
2021-11-21 03:17:10 +00:00
match : {
2021-11-22 09:10:25 +00:00
codec _id : "V_MPEG2" ,
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
legacy : "MPEG-1/2"
2021-11-21 03:17:10 +00:00
} ,
2021-11-25 18:07:42 +00:00
{
name : "MPEG-$version" ,
match : {
format : "MPEG Video" ,
format _version : /^Version (?<version>[12])$/ ,
} ,
legacy : "MPEG-1/2"
} ,
2021-11-21 03:17:10 +00:00
{
name : "h264" ,
match : {
2021-11-25 22:32:46 +00:00
codec _id : /^(V_MPEG4\/ISO\/AVC|avc1)$/ ,
2021-11-21 03:17:10 +00:00
bit _depth : "8 bits" ,
chroma _subsampling : /^4:2:0/
} ,
legacy : "h264"
} ,
{
2021-11-22 09:10:25 +00:00
name : "h264 $bitDepth-bit $chroma" ,
2021-11-21 03:17:10 +00:00
match : {
2021-11-25 22:32:46 +00:00
codec _id : /^(V_MPEG4\/ISO\/AVC|avc1)$/ ,
2021-11-22 09:10:25 +00:00
bit _depth : /^(?<bitDepth>10) bits/ ,
chroma _subsampling : /^(4:2:0|(?<chroma>[0-9]:[0-9]:[0-9]))/
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
legacy : "h264 $bitDepth-bit"
2021-11-21 03:17:10 +00:00
} ,
{
2021-11-22 09:10:25 +00:00
name : "VC-1 $codec" ,
2021-11-21 03:17:10 +00:00
match : {
2021-11-22 09:10:25 +00:00
codec _id : /^V_MS\/VFW\/FOURCC \/ (?<codec>WMV3|WMVA|WVC1)/ ,
bit _depth : "8 bits"
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
legacy : "VC-1"
2021-11-21 03:17:10 +00:00
} ,
{
2021-11-22 09:10:25 +00:00
name : "VP9 $chroma" ,
2021-11-21 03:17:10 +00:00
match : {
2021-11-22 09:10:25 +00:00
codec _id : "V_VP9" ,
bit _depth : "8 bits" ,
chroma _subsampling : /^(4:2:0|(?<chroma>[0-9]:[0-9]:[0-9]))/
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
legacy : "VP9"
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
2021-11-21 03:17:10 +00:00
{
2021-11-22 09:10:25 +00:00
name : "VP9 $bitDepth-bit $chroma" ,
2021-11-21 03:17:10 +00:00
match : {
2021-11-22 09:10:25 +00:00
codec _id : "V_VP9" ,
bit _depth : /^(?<bitDepth>10|12) bits/ ,
chroma _subsampling : /^(4:2:0|(?<chroma>[0-9]:[0-9]:[0-9]))/
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
legacy : "VP9"
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
2021-11-21 03:17:10 +00:00
{
2021-11-22 09:10:25 +00:00
name : "AV1 $chroma" ,
2021-11-21 03:17:10 +00:00
match : {
2021-11-25 22:32:46 +00:00
codec _id : /^(V_AV1$|av01)/ ,
2021-11-22 09:10:25 +00:00
bit _depth : "8 bits" ,
chroma _subsampling : /^(4:2:0|(?<chroma>[0-9]:[0-9]:[0-9]))/
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
legacy : "AV1"
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
2021-11-21 03:17:10 +00:00
{
2021-11-22 09:10:25 +00:00
name : "AV1 $bitDepth-bit $chroma" ,
2021-11-21 03:17:10 +00:00
match : {
2021-11-25 22:32:46 +00:00
codec _id : /^(V_AV1$|av01)/ ,
2021-11-22 09:10:25 +00:00
bit _depth : /^(?<bitDepth>10|12) bits/ ,
chroma _subsampling : /^(4:2:0|(?<chroma>[0-9]:[0-9]:[0-9]))/
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
legacy : "AV1"
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
2021-11-21 03:17:10 +00:00
{
2021-11-22 09:10:25 +00:00
name : "h265" ,
2021-11-21 03:17:10 +00:00
match : {
2021-11-25 22:32:46 +00:00
format : "HEVC" ,
2021-11-22 09:10:25 +00:00
bit _depth : "8 bits" ,
2021-11-21 03:17:10 +00:00
chroma _subsampling : /^4:2:0/
} ,
2021-11-22 09:10:25 +00:00
legacy : "h265"
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
2021-11-21 03:17:10 +00:00
{
2021-11-22 09:10:25 +00:00
name : "h265 $bitDepth-bit $chroma" ,
2021-11-21 03:17:10 +00:00
match : {
2021-11-25 22:32:46 +00:00
format : "HEVC" ,
bit _depth : /^(?<bitDepth>10|12) bits/ ,
chroma _subsampling : /^(4:2:0|(?<chroma>[0-9]:[0-9]:[0-9]))/
} ,
legacy : "h265 $bitDepth-bit"
} ,
{
name : "h265" ,
match : {
codec _id : /^(V_MPEGH\/ISO\/HEVC|hvc1|hev1)$/ ,
bit _depth : "8 bits" ,
chroma _subsampling : /^4:2:0/
} ,
legacy : "h265"
} ,
{
name : "h265 $bitDepth-bit $chroma" ,
match : {
codec _id : /^(V_MPEGH\/ISO\/HEVC|hvc1|hev1)$/ ,
2021-11-22 09:10:25 +00:00
bit _depth : /^(?<bitDepth>10|12) bits/ ,
chroma _subsampling : /^(4:2:0|(?<chroma>[0-9]:[0-9]:[0-9]))/
2021-11-21 03:17:10 +00:00
} ,
2021-11-22 09:10:25 +00:00
legacy : "h265 $bitDepth-bit"
2021-11-21 03:17:10 +00:00
} ,
2021-11-29 16:42:55 +00:00
{ //Fallback
name : "h265" ,
match : {
codec _id : /^(V_MPEGH\/ISO\/HEVC|hvc1|hev1)$/ ,
bit _depth : null ,
} ,
legacy : "h265"
} ,
{ //Fallback
name : "h265 $bitDepth-bit" ,
match : {
codec _id : /^(V_MPEGH\/ISO\/HEVC|hvc1|hev1)$/ ,
bit _depth : /^(?<bitDepth>10|12) bits/ ,
chroma _subsampling : null
} ,
legacy : "h265 $bitDepth-bit"
} ,
2021-11-21 03:17:10 +00:00
] ;
2021-11-29 16:42:55 +00:00
function makeAudioObject ( ob ) {
const channels = parseInt ( ( "channels" in ob ? ob . channels : ( "channel_count" in ob ? ob . channel _count : "1" ) ) . replace ( /[^0-9]/g , "" ) ) ;
ob . _ _audioCodec = matchCodecEntry ( audioCodecs , ob , {
name : "codec_id" in ob ? ob . codec _id : ob . format
} ) ;
Object . defineProperty ( ob , 'channels' , {
configurable : false ,
enumerable : true ,
get : ( ) => {
return channels ;
} ,
} ) ;
}
2021-11-25 22:32:46 +00:00
const matchSet = [
{
2021-11-25 23:11:24 +00:00
//Hidive
2021-11-25 22:32:46 +00:00
match : {
tags : {
sourceName : null ,
source : "Web"
} ,
audio : {
2021-11-25 23:14:12 +00:00
codec _id : /^A_AAC/
2021-11-25 23:11:24 +00:00
} ,
video : {
height : /^(720|(1 080)) pixels$/ ,
frame _rate _mode : "Constant" ,
writing _library : "x264 core 148" ,
encoding _settings : new RegExp ( "cabac=1 / ref=[36] / deblock=1:0:0 / analyse=0x3:0x113 / me=hex / subme=7 / psy=1 / psy_rd=1\\.00:0\\.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=(22|34) / lookahead_threads=[35] / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=3 / b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=1 / weightb=1 / open_gop=0 / weightp=2 / keyint=90 / keyint_min=9 / scenecut=0 / intra_refresh=0 / rc_lookahead=40 / rc=crf / mbtree=1 / crf=22\\.0 / qcomp=0\\.60 / qpmin=0 / qpmax=69 / qpstep=4 / vbv_maxrate=(11100|13500) / vbv_bufsize=(111000|135000) / crf_max=0\\.0 / nal_hrd=none / filler=0 / ip_ratio=1\\.40 / aq=1:1\\.00" )
} ,
text : {
2021-11-25 22:32:46 +00:00
2021-11-25 23:11:24 +00:00
}
} ,
set : {
sourceName : "Hidive"
}
} ,
{
//Crunchyroll new encoding settings for 480p/720p/1080p
match : {
tags : {
sourceName : null ,
source : "Web"
} ,
audio : {
2021-11-25 23:14:12 +00:00
codec _id : /^A_AAC/
2021-11-25 22:32:46 +00:00
} ,
video : {
height : /^(480|720|(1 080)) pixels$/ ,
frame _rate _mode : "Constant" ,
writing _library : "x264 core 142" ,
encoding _settings : new RegExp ( "cabac=1 / ref=[46] / deblock=1:1:1 / analyse=(0x1:0x111|0x3:0x113) / me=umh / subme=8 / psy=1 / psy_rd=0\\.40:0\\.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=[01] / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=(6|10|12) / lookahead_threads=[12] / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=0 / weightp=2 / keyint=96 / keyint_min=48 / scenecut=40 / intra_refresh=0 / rc_lookahead=48 / rc=2pass / mbtree=1 / bitrate=(2000|4000|8000) / ratetol=1\\.0 / qcomp=0\\.60 / qpmin=0 / qpmax=69 / qpstep=4 / cplxblur=20\\.0 / qblur=0\\.5 / vbv_maxrate=(3000|6000|12000) / vbv_bufsize=(4500|9000|18000) / nal_hrd=none / filler=0 / ip_ratio=1\\.40 / aq=1:0\\.60" )
} ,
text : {
}
} ,
set : {
sourceName : "Crunchyroll"
}
} ,
2021-11-26 04:42:57 +00:00
{
//Crunchyroll new crf encoding settings for 720p/1080p
match : {
tags : {
sourceName : null ,
source : "Web"
} ,
audio : {
codec _id : /^A_AAC/
} ,
video : {
height : /^(720|(1 080)) pixels$/ ,
frame _rate _mode : "Constant" ,
writing _library : "x264 core 142" ,
encoding _settings : new RegExp ( "cabac=1 / ref=[46] / deblock=1:1:1 / analyse=0x3:0x113 / me=umh / subme=8 / psy=1 / psy_rd=0\\.40:0\\.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=(10|12|16) / lookahead_threads=[12] / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=3 / b_pyramid=2 / b_adapt=2 / b_bias=0 / direct=3 / weightb=1 / open_gop=0 / weightp=2 / keyint=48 / keyint_min=24 / scenecut=40 / intra_refresh=0 / rc_lookahead=48 / rc=crf / mbtree=1 / crf=(15\\.0|16\\.0) / qcomp=0\\.60 / qpmin=0 / qpmax=69 / qpstep=4 / vbv_maxrate=(4000|8000) / vbv_bufsize=(6000|12000) / crf_max=0\\.0 / nal_hrd=none / filler=0 / ip_ratio=1\\.40 / aq=1:0\\.60" )
} ,
text : {
}
} ,
set : {
sourceName : "Crunchyroll"
}
} ,
2021-11-25 22:32:46 +00:00
{
//Crunchyroll old encoding settings for 480p/720p/1080p
match : {
tags : {
sourceName : null ,
source : "Web"
} ,
audio : {
2021-11-25 23:14:12 +00:00
codec _id : /^A_AAC/
2021-11-25 22:32:46 +00:00
} ,
video : {
height : /^(480|720|(1 080)) pixels$/ ,
frame _rate _mode : "Constant" ,
writing _library : "x264 core 120 r2120 0c7dab9" ,
2021-11-26 04:42:57 +00:00
encoding _settings : new RegExp ( "cabac=1 / ref=[46] / deblock=1:1:1 / analyse=(0x1:0x111|0x3:0x113) / me=umh / subme=8 / psy=1 / psy_rd=0\\.40:0\\.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=[01] / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=[48] / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=3 / b_pyramid=2 / b_adapt=2 / b_bias=0 / direct=3 / weightb=1 / open_gop=0 / weightp=2 / keyint=250 / keyint_min=(23|25) / scenecut=40 / intra_refresh=0 / rc_lookahead=50 / rc=2pass / mbtree=1 / bitrate=(768|1776|3072|3088) / ratetol=1\\.0 / qcomp=0\\.60 / qpmin=0 / qpmax=69 / qpstep=4 / cplxblur=20\\.0 / qblur=0\\.5 / vbv_maxrate=(1536|3552|6144|6176) / vbv_bufsize=(3840|8880|15360|15440) / nal_hrd=none / ip_ratio=1\\.40 / aq=1:0\\.60" )
2021-11-25 22:32:46 +00:00
} ,
text : {
}
} ,
set : {
sourceName : "Crunchyroll"
}
} ,
2021-11-26 04:42:57 +00:00
{
//Funimation 360p/720p/1080p
match : {
tags : {
sourceName : null ,
source : "Web"
} ,
audio : {
codec _id : /^A_AAC/
} ,
video : {
height : /^(360|720|(1 080)) pixels$/ ,
frame _rate _mode : "Constant" ,
writing _library : "x264 core 157 r2948 dada181" ,
encoding _settings : new RegExp ( "cabac=[01] / ref=1 / deblock=1:0:0 / analyse=(0x1:0x111|0x3:0x113) / me=hex / subme=7 / psy=1 / psy_rd=1\\.00:0\\.00 / mixed_ref=0 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=[01] / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=(11|12|22|24) / lookahead_threads=[1-4] / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=[02] / ((b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=1 / weightb=1 / open_gop=0 / )|)weightp=[02] / keyint=48 / keyint_min=4 / scenecut=40 / intra_refresh=0 / rc_lookahead=40 / rc=cbr / mbtree=1 / bitrate=(1200|3500|8000) / ratetol=1\\.0 / qcomp=0\\.60 / qpmin=0 / qpmax=69 / qpstep=4 / vbv_maxrate=(1200|3500|8000) / vbv_bufsize=(3600|10500|24000) / nal_hrd=none / filler=0 / ip_ratio=1\\.40 / aq=1:1\\.00" )
} ,
text : {
}
} ,
set : {
sourceName : "Funimation"
}
} ,
2021-11-25 23:11:24 +00:00
{
//bilibili
match : {
tags : {
sourceName : null ,
source : "Web"
} ,
audio : {
2021-11-25 23:14:12 +00:00
codec _id : /^A_AAC/
2021-11-25 23:11:24 +00:00
} ,
video : {
frame _rate _mode : "Constant" ,
writing _library : /^BiliBili H264 Encoder v[0-9.\-]+$/ ,
encoding _settings : null
} ,
text : {
}
} ,
set : {
sourceName : "bilibili"
}
} ,
{
//Netflix?
match : {
tags : {
sourceName : null ,
source : "Web"
} ,
audio : {
2021-11-26 05:14:37 +00:00
codec _id : /^A_E?AC3$/ ,
2021-11-25 23:11:24 +00:00
} ,
video : {
height : /^(720|(1 080)) pixels$/ ,
frame _rate _mode : "Constant" ,
bit _rate _mode : "Variable" ,
2021-11-26 05:14:37 +00:00
writing _library : /^x264 core 148 r[0-9]+ [0-9a-f]+$/ ,
2021-11-26 04:51:26 +00:00
encoding _settings : new RegExp ( "cabac=1 / ref=3 / deblock=1:0:0 / analyse=0x1:0x111 / me=umh / subme=10 / psy=1 / psy_rd=1\\.00:0\\.00 / mixed_ref=1 / me_range=24 / chroma_me=1 / trellis=2 / 8x8dct=0 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=[68] / lookahead_threads=1 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / stitchable=1 / constrained_intra=0 / bframes=2 / b_pyramid=0 / b_adapt=2 / b_bias=0 / direct=3 / weightb=1 / open_gop=0 / weightp=2 / keyint=250 / keyint_min=(23|24) / scenecut=0 / intra_refresh=0 / rc_lookahead=48 / rc=2pass / mbtree=1 / bitrate=[0-9]+ / ratetol=1\\.0 / qcomp=0\\.50 / qpmin=6 / qpmax=51 / qpstep=4 / cplxblur=20\\.0 / qblur=0\\.5 / vbv_maxrate=[0-9]+ / vbv_bufsize=[0-9]+ / nal_hrd=vbr / filler=0 / ip_ratio=1\\.40 / aq=1:1\\.00" )
2021-11-25 23:11:24 +00:00
}
} ,
set : {
sourceName : "Netflix*"
}
} ,
2021-11-26 04:42:57 +00:00
{
//Amazon Prime Video?
match : {
tags : {
sourceName : null ,
source : "Web"
} ,
audio : {
codec _id : /^(A_AAC|A_EAC3$)/
} ,
video : {
codec _id : "V_MPEG4/ISO/AVC" ,
format _profile : /^((High@(L4|L3\.1))|Main@L3)$/ ,
format _settings _cabac : "Yes" ,
frame _rate _mode : "Constant" ,
writing _library : null ,
encoding _settings : null ,
color _range : "Limited" ,
color _primaries : "BT.709" ,
transfer _characteristics : "BT.709" ,
matrix _coefficients : "BT.709"
} ,
custom : ( torrent , mediainfo , tags , video , audio , text ) => {
2021-11-29 16:42:55 +00:00
let match = ( mediainfo . audio . length === 1 && "codec_id" in mediainfo . audio [ 0 ] && mediainfo . audio [ 0 ] . codec _id . match ( /^A_EAC3$/ ) !== null ) ||
( mediainfo . audio . length === 2 && "codec_id" in mediainfo . audio [ 0 ] && "codec_id" in mediainfo . audio [ 1 ] && mediainfo . audio [ 0 ] . codec _id . match ( /^(A_AAC|^A_EAC3$)/ ) !== null && mediainfo . audio [ 1 ] . codec _id . match ( /^A_EAC3$/ ) !== null ) ;
2021-11-26 04:42:57 +00:00
if ( match ) {
let eac3Track = mediainfo . audio [ 0 ] . codec _id . match ( /^A_EAC3$/ ) !== null ? mediainfo . audio [ 0 ] : ( ( mediainfo . audio . length > 1 && mediainfo . audio [ 1 ] . codec _id . match ( /^A_EAC3$/ ) !== null ) ? mediainfo . audio [ 1 ] : null ) ;
if ( eac3Track === null ) {
match = false ;
}
if ( "bit_rate_mode" in video && video . bit _rate _mode !== "Constant" ) {
match = false ;
}
switch ( parseInt ( video . width . replace ( /[^0-9]/g , "" ) ) ) {
case 1920 :
if ( "nominal_bit_rate" in video && video . nominal _bit _rate !== "10 000 kb/s" ) {
match = false ;
}
if ( video . format _profile !== "High@L4" ) {
match = false ;
}
if ( ( "format_settings_reframes" in video && video . format _settings _reframes !== "4 frames" ) || ( "format_settings_reference_frames" in video && video . format _settings _reference _frames !== "4 frames" ) ) {
match = false ;
}
break ;
case 1280 :
if ( "nominal_bit_rate" in video && video . nominal _bit _rate !== "4 000 kb/s" ) {
match = false ;
}
if ( video . format _profile !== "High@L3.1" ) {
match = false ;
}
if ( ( "format_settings_reframes" in video && video . format _settings _reframes !== "5 frames" ) || ( "format_settings_reference_frames" in video && video . format _settings _reference _frames !== "5 frames" ) ) {
match = false ;
}
break ;
case 720 :
/ * i f ( " n o m i n a l _ b i t _ r a t e " i n v i d e o & & v i d e o . n o m i n a l _ b i t _ r a t e ! = = " 4 0 0 0 k b / s " ) {
match = false ;
} * /
if ( video . format _profile !== "Main@L3" ) {
match = false ;
}
if ( ( "format_settings_reframes" in video && video . format _settings _reframes !== "5 frames" ) || ( "format_settings_reference_frames" in video && video . format _settings _reference _frames !== "5 frames" ) ) {
match = false ;
}
break ;
default :
match = false ;
}
2021-11-29 16:42:55 +00:00
switch ( eac3Track . channels ) {
2021-11-26 04:42:57 +00:00
case 2 :
if ( "bit_rate_mode" in eac3Track && eac3Track . bit _rate _mode !== "Constant" ) {
match = false ;
}
if ( "bit_rate" in eac3Track && eac3Track . bit _rate !== "224 kb/s" ) {
match = false ;
}
if ( "number_of_dynamic_objects" in eac3Track ) { //No Atmos
match = false ;
}
break ;
case 6 :
if ( "bit_rate_mode" in eac3Track && eac3Track . bit _rate _mode !== "Constant" ) {
match = false ;
}
if ( "bit_rate" in eac3Track && eac3Track . bit _rate !== "640 kb/s" ) {
match = false ;
}
if ( "number_of_dynamic_objects" in eac3Track ) { //No Atmos
match = false ;
}
break ;
default :
match = false ;
}
}
return match ;
} ,
} ,
set : {
sourceName : "Amazon Prime Video*"
}
} ,
2021-11-29 16:42:55 +00:00
] ;
function matchCodecEntry ( codecs , ob , fallback = null ) {
let matchObject = fallback ;
codecs . every ( ( codec ) => {
let match = true ;
let n = codec . name ;
let l = codec . legacy ;
let m = null ;
for ( const [ key , value ] of Object . entries ( codec . match ) ) {
if ( value === null ) {
if ( key in ob ) {
match = false ;
break ;
}
continue ;
}
if ( ! ( key in ob ) ) {
match = false ;
break ;
} else if ( value instanceof RegExp ) {
if ( ( m = ob [ key ] . match ( value ) ) === null ) {
match = false ;
break ;
}
if ( "groups" in m && typeof m . groups === "object" ) {
for ( const [ k , v ] of Object . entries ( m . groups ) ) {
if ( typeof v !== "undefined" ) {
n = n . replace ( '$' + k , v ) ;
l = l . replace ( '$' + k , v ) ;
} else {
n = n . replace ( '$' + k , "" ) ;
l = l . replace ( '$' + k , "" ) ;
}
}
}
} else if ( ! ( value instanceof RegExp ) && ob [ key ] !== value ) {
match = false ;
break ;
}
}
if ( match ) {
matchObject = Object . assign ( { } , codec ) ;
matchObject . name = n . trim ( ) ;
matchObject . legacy = l . trim ( ) ;
}
return ! match ;
} ) ;
return matchObject ;
}
2021-11-25 22:32:46 +00:00
2021-11-29 18:02:16 +00:00
let settings = {
} ;
function addSetting ( id , name , description , type , defaultValue ) {
let v = GM _getValue ( id , defaultValue ) ;
switch ( type ) {
case "bool" :
v = ! ! v ;
break ;
case "string" :
v = "" + v ;
break ;
case "int" :
v = parseInt ( v ) ;
break ;
}
settings [ id ] = {
id : id ,
type : type ,
value : v ,
name : name ,
description : description
} ;
}
function setSetting ( id , value ) {
if ( ! ( id in settings ) ) {
throw "Unknown setting " + id ;
}
switch ( settings . type ) {
case "bool" :
value = ! ! v ;
break ;
case "string" :
value = "" + value ;
break ;
case "int" :
value = parseInt ( value ) ;
break ;
}
settings [ id ] . value = value ;
GM _setValue ( id , value ) ;
}
function getSetting ( id ) {
if ( ! ( id in settings ) ) {
throw "Unknown setting " + id ;
}
return settings [ id ] . value
}
addSetting ( "enhanceTags" , "Enhance Tags" , "Entries will have their tags replaced/extended. Formats (like Atmos, HDR, higher bitDepth, chroma) and detected Sources will be labeled accordingly. Disabling this removes most of this scripts functions." , "bool" , true ) ;
addSetting ( "regexpFilter" , "RegExp Filter" , "Any entry that matches this regex (without delimiters) will be filtered out. Empty to disable" , "string" , "" ) ;
addSetting ( "warning_mediainfoSource" , "General: Mediainfo Source" , "Alert when Mediainfo was found on Description and not on Mediainfo tab." , "bool" , true ) ;
addSetting ( "warning_mediainfoInvalid" , "General: Mediainfo not found" , "Alert when Mediainfo was not found or invalid" , "bool" , true ) ;
addSetting ( "warning_tagMismatch" , "General: Mismatched Tags" , "Alert when site tags differ from calculated tags" , "bool" , true ) ;
addSetting ( "warning_orderedChapters" , "General: Ordered Chapters" , "Warn when Ordered Chapters are found" , "bool" , true ) ;
addSetting ( "warning_japaneseNumbering" , "General: Japanese Episode Numbering" , "Inform when episodes are labeled in Japanese. Example: 第02話" , "bool" , true ) ;
addSetting ( "warning_hwEncoder" , "Video: Hardware Encoded" , "Alert when a hardware encoder is found on a release." , "bool" , true ) ;
addSetting ( "warning_encodeProfile" , "Video: Profile" , "Warn when low encoding profile is found on encode settings." , "bool" , true ) ;
addSetting ( "warning_encodeSettings" , "Video: Settings" , "Inform when a non-optimal setting is found on encode settings." , "bool" , true ) ;
addSetting ( "warning_defaultAudioNotJapanese" , "Audio: Default not Japanese" , "Inform when Default audio is not Japanese (Does not apply to Live Action)" , "bool" , true ) ;
addSetting ( "warning_bloatPCM" , "Audio: bloat, PCM" , "Warn when any audio track is left as PCM (Does not apply to remux or raw sources)" , "bool" , true ) ;
addSetting ( "warning_bloatg16bit" , "Audio: bloat, >16-bit" , "Warn when specific lossless audio has bit depth larger than 16-bit (Does not apply to remux or raw sources)" , "bool" , true ) ;
addSetting ( "warning_signsDefault" , "Text: Default is Signs" , "Warn when Default track is a known Signs track" , "bool" , true ) ;
addSetting ( "warning_externalSubs" , "Text: External Subtitles" , "Warn when only external subtitles are present" , "bool" , true ) ;
const torrentTypeImage = document . querySelector ( "a.scaledImg > img" ) ;
const torrentType = torrentTypeImage ? torrentTypeImage . getAttribute ( "title" ) : null ;
2021-11-25 18:07:42 +00:00
const torrentTableColspan = 6 ;
2021-11-29 18:02:16 +00:00
if ( torrentType !== null && allowedVideoTypes . indexOf ( torrentType . replace ( "Live Action " , "" ) ) !== - 1 ) {
2021-11-25 18:07:42 +00:00
//Make page wider
2021-11-29 18:02:16 +00:00
2021-11-21 03:17:10 +00:00
let episodeCount = 0 ;
document . querySelectorAll ( "ul.stats > li" ) . forEach ( ( item ) => {
let strongItem = item . querySelector ( "strong" ) ;
if ( strongItem !== null && strongItem . textContent === "Episodes:" ) {
episodeCount = parseInt ( item . querySelector ( "a" ) . textContent ) ;
}
} ) ;
2021-11-25 18:53:41 +00:00
if ( episodeCount === 0 && torrentType . match ( /Movie$/ ) !== null ) {
2021-11-21 03:17:10 +00:00
episodeCount = 1 ;
}
let torrentListing = [ ] ;
document . querySelectorAll ( ".group_torrent" ) . forEach ( ( item ) => {
2021-11-25 21:12:43 +00:00
const downloadLink = item . querySelector ( "td > span > a[title^='Download']" ) ;
const linkSection = downloadLink . parentElement . parentElement ;
2021-11-21 03:17:10 +00:00
const [ torrentEntry ] = Array . from ( linkSection . querySelectorAll ( "a" ) ) . slice ( - 1 ) ;
const torrentId = parseInt ( downloadLink . getAttribute ( "href" ) . match ( /\/torrent\/(?<torrent_id>[0-9]+)\/download/ ) . groups . torrent _id ) ;
2021-11-25 21:12:43 +00:00
if ( ! torrentEntry ) {
//Skip unknown entries
return ;
}
2021-11-21 03:17:10 +00:00
let tags = {
audioCount : 1 ,
2021-11-21 13:15:27 +00:00
freeleech : torrentEntry . querySelector ( "img[alt^='Freeleech!']" ) !== null ,
remastered : torrentEntry . querySelector ( "img[alt^='Remastered']" ) !== null ,
2021-11-21 03:17:10 +00:00
snatched : torrentEntry . textContent . match ( / - Snatched/ ) !== null
} ;
torrentEntry . textContent . replace ( "»" , "" ) . replace ( " - Snatched" , "" ) . split ( " | " ) . forEach ( ( t ) => {
let tagEntry = t . trim ( ) ;
if ( tagEntry === "" ) {
return ;
}
let match = null ;
if ( ! ( "source" in tags ) && knownSources . indexOf ( tagEntry ) !== - 1 ) {
tags . source = tagEntry ;
} else if ( ! ( "container" in tags ) && knownContainers . some ( ( i ) => tagEntry . startsWith ( i ) ) ) {
if ( ( match = tagEntry . match ( /^(?<container>[^(]+) \((?<region>[^)]+)\)$/ ) ) !== null ) {
tags . container = match . groups . container ;
tags . region = match . groups . region ;
} else {
tags . container = tagEntry ;
}
} else if ( ! ( "videoCodec" in tags ) && knownVideoCodecs . some ( ( i ) => tagEntry . startsWith ( i ) ) ) {
tags . videoCodec = tagEntry ;
} else if ( ! ( "audioCodec" in tags ) && knownAudioCodecs . some ( ( i ) => tagEntry . startsWith ( i ) ) ) {
match = tagEntry . match ( /^(?<codec>.+) (?<channels>[0-9.]+)$/ )
tags . audioCodec = match . groups . codec ;
tags . audioChannels = match . groups . channels . split ( "." ) . reduce ( ( p , c ) => parseInt ( p ) + parseInt ( c ) ) ;
} else if ( tagEntry . match ( /^[0-9]+:[0-9]+$/ ) !== null ) {
tags . aspectRatio = tagEntry ;
} else if ( tagEntry . match ( /^[0-9]+x[0-9]+$/ ) !== null || tagEntry . match ( /^(720p|1080p|1080i|4K)$/ ) !== null ) {
tags . resolution = tagEntry ;
} else if ( tagEntry === "Dual Audio" ) {
tags . audioCount = 2 ;
} else if ( ( match = tagEntry . match ( /^(?<kind>(RAW|Hardsubs|Softsubs))( \()?(?<group>[^)]*)(\))?$/ ) ) !== null ) {
if ( match . groups . kind !== "RAW" ) {
tags . subtitleType = match . groups . kind ;
}
if ( match . groups . group !== "" ) {
tags . group = match . groups . group ;
}
} else {
//console.log(tagEntry);
}
} ) ;
let torrent = {
id : torrentId ,
tags : tags ,
elements : {
item : item ,
entry : torrentEntry ,
link : downloadLink ,
} ,
} ;
const dataSection = document . getElementById ( "torrent_" + torrentId ) ;
if ( dataSection !== null ) {
2021-11-25 18:07:42 +00:00
torrent . elements . data = dataSection ;
2021-11-21 03:17:10 +00:00
const descriptionSection = document . getElementById ( torrentId + "_description" ) ;
const filelistSection = document . getElementById ( torrentId + "_filelist" ) ;
const mediaInfoSection = document . getElementById ( torrentId + "_mediainfo" ) ;
if ( descriptionSection !== null ) {
torrent . elements . description = descriptionSection . querySelector ( "blockquote" ) ;
torrent . description = torrent . elements . description . textContent ;
}
if ( filelistSection !== null ) {
torrent . elements . filelist = filelistSection . querySelector ( "table" ) ;
torrent . filelist = [ ] ;
torrent . elements . filelist . querySelectorAll ( "tr" ) . forEach ( ( tableRow ) => {
if ( tableRow . querySelector ( "td > strong" ) !== null ) {
//Skip header
return ;
}
torrent . filelist . push ( {
path : tableRow . querySelector ( "td" ) . textContent ,
size : tableRow . querySelector ( "td:last-of-type" ) . textContent //TODO: convert back to bytes
} )
} ) ;
}
if ( mediaInfoSection !== null ) {
torrent . elements . mediainfo = mediaInfoSection ;
let m _list = [ ] ;
torrent . elements . mediainfo . querySelectorAll ( "pre" ) . forEach ( ( mediainfoItem ) => {
let m = parseMediaInfo ( mediainfoItem . textContent ) ;
if ( m !== null ) {
m _list . push ( m ) ;
}
} ) ;
if ( m _list . length > 0 ) {
torrent . mediainfo = m _list ;
2021-11-21 14:06:34 +00:00
torrent . mediainfoSource = "mediainfo" ;
}
} else if ( descriptionSection !== null ) {
//Find mediainfo tags
torrent . elements . description . querySelectorAll ( "input.spoilerButton" ) . forEach ( ( e ) => {
let t = e . parentElement . querySelector ( "div.spoiler" ) . textContent . trim ( ) ;
if ( t . indexOf ( "General" ) === 0 ) {
let m = parseMediaInfo ( t ) ;
if ( m !== null ) {
if ( ! ( "mediainfo" in torrent ) ) {
torrent . mediainfo = [ ] ;
torrent . mediainfoSource = "description spoiler" ;
}
torrent . mediainfo . push ( m ) ;
}
}
} ) ;
2021-11-21 14:51:42 +00:00
if ( ! ( "mediainfo" in torrent ) ) {
//Fallback, find General tag
let t = torrent . elements . description . parentElement . textContent . trim ( ) ;
let index = t . indexOf ( "General" ) ;
if ( index !== - 1 ) {
let m = parseMediaInfo ( t . substr ( index ) ) ;
if ( m !== null ) {
if ( ! ( "mediainfo" in torrent ) ) {
torrent . mediainfo = [ ] ;
torrent . mediainfoSource = "description" ;
}
torrent . mediainfo . push ( m ) ;
2021-11-21 14:06:34 +00:00
}
}
2021-11-21 03:17:10 +00:00
}
}
torrentListing . push ( torrent ) ;
}
} ) ;
2021-11-25 18:07:42 +00:00
{
{
2021-11-25 21:27:21 +00:00
let parentTd = document . querySelector ( "table.torrent_table tr > td[width*='%']" ) ;
2021-11-25 18:07:42 +00:00
parentTd . insertAdjacentElement ( "beforebegin" , document . createElement ( "td" ) ) ;
// Source + container + remux | Codec / Resolution / HDR | Audio + Dual + commentary | Text | OtherTags | Icons
parentTd . setAttribute ( "colspan" , torrentTableColspan . toString ( ) ) ;
2021-11-25 19:24:56 +00:00
parentTd . style [ "width" ] = "fit-content" ;
parentTd . style [ "max-width" ] = "80%" ;
2021-11-25 18:07:42 +00:00
document . querySelectorAll ( "table.torrent_table tr.edition_info > td" ) . forEach ( ( e ) => {
2021-11-25 21:27:21 +00:00
e . setAttribute ( "colspan" , ( e . getAttribute ( "colspan" ) + torrentTableColspan ) . toString ( ) ) ;
2021-11-25 18:07:42 +00:00
} ) ;
}
torrentListing . forEach ( ( torrent ) => {
let parent = torrent . elements . link . parentElement ;
let td = document . createElement ( "td" ) ;
2021-11-25 21:27:21 +00:00
let element = torrent . elements . data . querySelector ( "td" ) ;
element . setAttribute ( "colspan" , ( element . getAttribute ( "colspan" ) + torrentTableColspan ) . toString ( ) ) ;
2021-11-25 18:07:42 +00:00
parent . parentElement . insertAdjacentElement ( "beforebegin" , td ) ;
parent . style [ "white-space" ] = "nowrap" ;
td . append ( parent ) ;
Array . from ( parent . childNodes ) . forEach ( ( e ) => {
if ( e . nodeType === Node . TEXT _NODE && [ "[" , "]" ] . includes ( e . textContent . trim ( ) ) ) {
e . remove ( ) ;
}
} ) ;
} ) ;
}
2021-11-25 18:53:41 +00:00
let contentStyle = document . getElementById ( "content" ) . style ;
contentStyle [ "max-width" ] = "calc(100% - 50px)" ;
contentStyle [ "width" ] = "fit-content" ;
2021-11-25 19:16:58 +00:00
GM _addStyle ( "#content{ max-width: calc(100% - 50px); width: fit-content; }" ) ;
2021-11-29 15:12:30 +00:00
GM _addStyle ( "table.torrent_table { width: fit-content; min-width: calc(950px - 240px); }" ) ;
2021-11-25 19:16:58 +00:00
//Fix delicious user scripts
2021-11-29 18:02:16 +00:00
GM _addStyle ( "div.torrent_filter_box { width: fit-content !important; float: none !important; min-width: calc(950px - 240px); }" ) ;
2021-11-25 18:53:41 +00:00
const torrentTableElement = document . querySelector ( "div#content table.torrent_table" ) ;
const resizeCallback = ( ) => {
document . querySelectorAll ( "#torrents div.main_column > table:not(.torrent_table), #torrents div.main_column > div" ) . forEach ( ( e ) => {
e . style [ "width" ] = torrentTableElement . offsetWidth + "px" ;
} ) ;
} ;
const tableResizeObserver = new ResizeObserver ( resizeCallback ) ;
tableResizeObserver . observe ( torrentTableElement ) ;
resizeCallback ( ) ;
2021-11-21 03:17:10 +00:00
console . log ( torrentListing ) ;
torrentListing . forEach ( ( torrent ) => {
try {
2021-11-25 18:07:42 +00:00
let infoCount = 0 ;
let warningCount = 0 ;
let dangerCount = 0 ;
let tags = {
} ;
let warnings = {
general : [ ] ,
audio : [ ] ,
video : [ ] ,
text : [ ]
}
let fileName = null ;
if ( "mediainfo" in torrent && torrent . mediainfo . length > 0 && "mediainfo.general.complete_name" in torrent . mediainfo [ 0 ] . general ) {
[ fileName ] = torrent . mediainfo [ 0 ] . general . complete _name . split ( "/" ) . slice ( - 1 ) ;
} else {
fileName = torrent . filelist [ 0 ] . path ;
}
//handle file tags
fileName . split ( "." ) . forEach ( ( p ) => {
2021-11-25 22:32:46 +00:00
if ( p . toUpperCase ( ) === "NF" || p . toUpperCase ( ) === "NETFLIX" ) {
2021-11-25 18:07:42 +00:00
tags . sourceName = "Netflix" ;
2021-11-25 22:32:46 +00:00
} else if ( p . toUpperCase ( ) === "CR" || p . toUpperCase ( ) === "CRUNCHYROLL" ) {
tags . sourceName = "Crunchyroll" ;
2021-11-25 18:07:42 +00:00
} else if ( p . toUpperCase ( ) === "ATVP" ) {
tags . sourceName = "Apple TV+" ;
2021-11-25 22:32:46 +00:00
} else if ( p . toUpperCase ( ) === "DSNP" ) {
tags . sourceName = "Disney Plus" ;
} else if ( p . toUpperCase ( ) === "AMZN" || p . toUpperCase ( ) === "AMAZON" ) {
tags . sourceName = "Amazon Prime Video" ;
} else if ( p . toUpperCase ( ) === "FUNI" || p . toUpperCase ( ) === "FUNIMATION" ) {
tags . sourceName = "Funimation" ;
2021-11-26 04:42:57 +00:00
} else if ( p . toUpperCase ( ) === "WAKANIM" ) {
tags . sourceName = "Wakanim" ;
} else if ( p . toUpperCase ( ) === "ANIMELAB" ) {
tags . sourceName = "AnimeLab" ;
2021-11-25 22:32:46 +00:00
} else if ( p . toUpperCase ( ) === "HIDIVE" ) {
tags . sourceName = "Hidive" ;
} else if ( p . toUpperCase ( ) === "VRV" ) {
tags . sourceName = "VRV" ;
} else if ( p . toUpperCase ( ) === "HULU" ) {
tags . sourceName = "Hulu" ;
2021-11-25 18:07:42 +00:00
} else if ( p === "HDR" ) {
tags . videoHDR = "HDR" ;
} else if ( p === "HDR10" ) {
tags . videoHDR = "HDR10" ;
} else if ( p === "DV" ) {
tags . videoHDR = "HDR DV" ;
} else if ( p . toUpperCase ( ) === "REMUX" ) {
tags . remux = true ;
}
} ) ;
2021-11-25 22:32:46 +00:00
fileName . split ( /[ _\[(\])]/ ) . forEach ( ( p ) => {
if ( torrent . tags . source === "Web" && ( p . toUpperCase ( ) === "NF" || p . toUpperCase ( ) === "NETFLIX" ) ) {
2021-11-25 18:07:42 +00:00
tags . sourceName = "Netflix" ;
2021-11-25 22:32:46 +00:00
} else if ( torrent . tags . source === "Web" && ( p . toUpperCase ( ) === "CR" || p . toUpperCase ( ) === "CRUNCHYROLL" || p . toUpperCase ( ) === "CR-DUB" ) ) {
tags . sourceName = "Crunchyroll" ;
} else if ( torrent . tags . source === "Web" && ( p . toUpperCase ( ) === "AMZN" || p . toUpperCase ( ) === "AMAZON" ) ) {
tags . sourceName = "Amazon Prime Video" ;
} else if ( torrent . tags . source === "Web" && p . toUpperCase ( ) === "HULU" ) {
tags . sourceName = "Hulu" ;
} else if ( torrent . tags . source === "Web" && ( p . toUpperCase ( ) === "FUNIMATION" || p . toUpperCase ( ) === "FUNI" || p . toUpperCase ( ) === "FUNIDUB" || p . toUpperCase ( ) === "FUNI-DUB" ) ) {
tags . sourceName = "Funimation" ;
} else if ( torrent . tags . source === "Web" && ( p . toUpperCase ( ) === "HIDIVE" || p . toUpperCase ( ) === "HIDIVE-DUB" ) ) {
tags . sourceName = "Hidive" ;
} else if ( torrent . tags . source === "Web" && p . toUpperCase ( ) === "VRV" ) {
tags . sourceName = "Hidive" ;
2021-11-25 18:07:42 +00:00
} else if ( p === "HDR" ) {
tags . videoHDR = "HDR" ;
} else if ( p === "HDR10" ) {
tags . videoHDR = "HDR10" ;
} else if ( p === "DV" ) {
tags . videoHDR = "HDR DV" ;
} else if ( p . toUpperCase ( ) . indexOf ( "REMUX" ) !== - 1 ) {
tags . remux = true ;
}
} ) ;
2021-11-25 18:13:36 +00:00
let japaneseEpisodeMatch = fileName . match ( /第[0-9.]+話/u ) ;
2021-11-29 18:02:16 +00:00
if ( japaneseEpisodeMatch !== null && getSetting ( "warning_japaneseNumbering" ) ) {
2021-11-25 18:16:02 +00:00
warnings . general . push ( [ "info" , "Episode numbering is in Japanese format: example " + japaneseEpisodeMatch [ 0 ] ] ) ;
2021-11-25 18:13:36 +00:00
}
2021-11-21 03:17:10 +00:00
if ( "mediainfo" in torrent && torrent . mediainfo . length > 0 ) {
let mediainfo = torrent . mediainfo [ 0 ] ;
let japaneseAudio = null ;
let otherAudio = null ;
let defaultAudio = null ;
let englishSubs = null ;
let defaultSubs = null ;
switch ( mediainfo . general . format ) {
case "Matroska" :
tags . container = "MKV" ;
break ;
case "BDAV" :
tags . container = "M2TS" ;
break ;
}
2021-11-29 18:02:16 +00:00
if ( torrent . mediainfoSource !== "mediainfo" && getSetting ( "warning_mediainfoSource" ) ) {
2021-11-21 14:06:34 +00:00
warnings . general . push ( [ "danger" , "Mediainfo sourced from " + torrent . mediainfoSource + ". Consider reporting the torrent and providing it." ] )
}
2021-11-21 03:17:10 +00:00
2021-11-26 09:28:35 +00:00
let video = null ;
mediainfo . video . every ( ( v ) => {
if ( "default" in v && v . default === "Yes" ) {
video = v ;
return false ;
}
return true ;
} ) ;
if ( video === null && mediainfo . video . length > 0 ) {
video = mediainfo . video [ 0 ] ;
}
tags . videoCount = mediainfo . video . length ;
2021-11-21 03:17:10 +00:00
if ( video !== null ) {
2021-11-29 16:42:55 +00:00
tags . videoCodec = matchCodecEntry ( videoCodecs , video , torrent . tags . videoCodec ) ;
2021-11-21 03:17:10 +00:00
2021-11-21 13:15:27 +00:00
if ( "frame_rate" in video ) {
tags . videoFrameRate = video . frame _rate . split ( " " ) [ 0 ] ;
} else
if ( "original_frame_rate" in video ) {
tags . videoFrameRate = video . original _frame _rate . split ( " " ) [ 0 ] ;
}
2021-11-21 03:17:10 +00:00
let width = parseInt ( video . width . replace ( /[^0-9]/g , "" ) ) ;
let height = parseInt ( video . height . replace ( /[^0-9]/g , "" ) ) ;
2021-11-21 13:15:27 +00:00
if ( ( ( width <= 1280 && width >= 1200 ) || ( width <= 960 && width >= 900 ) ) && height > 480 && height <= 720 ) {
2021-11-21 03:17:10 +00:00
tags . resolution = "720" + ( ( ! ( "scan_type" in video ) || video . scan _type === "Progressive" ) ? "p" : "i" ) ;
2021-11-21 13:15:27 +00:00
} else if ( ( ( width <= 1920 && width >= 1820 ) || ( width <= 1440 && width >= 1340 ) ) && height > 720 && height <= 1080 ) {
2021-11-21 03:17:10 +00:00
tags . resolution = "1080" + ( ( ! ( "scan_type" in video ) || video . scan _type === "Progressive" ) ? "p" : "i" ) ;
2021-11-21 13:15:27 +00:00
} else if ( ( width <= 3840 && width >= 3640 ) && height > 1080 && height <= 2160 ) {
2021-11-21 03:17:10 +00:00
tags . resolution = "4K" ;
} else {
tags . resolution = width + "x" + height ;
}
2021-11-25 19:53:01 +00:00
if ( "display_aspect_ratio" in video ) {
tags . aspectRatio = video . display _aspect _ratio . replace ( "/" , ":" ) ;
}
2021-11-21 13:15:27 +00:00
2021-11-21 03:17:10 +00:00
if ( "color_primaries" in video && video . color _primaries === "BT.2020" ) {
tags . videoHDR = "HDR" ;
}
if ( "hdr_format" in video ) {
if ( video . hdr _format . match ( /Dolby Vision/ ) !== null ) {
tags . videoHDR = "HDR DV" ;
} else if ( video . hdr _format . match ( /SMPTE ST 2086/ ) !== null && video . hdr _format . match ( /HDR10/ ) !== null ) {
tags . videoHDR = "HDR10" ;
} else if ( video . hdr _format . match ( /SMPTE ST 2094-40/ ) !== null && video . hdr _format . match ( /HDR10/ ) !== null ) {
tags . videoHDR = "HDR10+" ;
} else if ( video . hdr _format . match ( /SL-HDR1/ ) !== null ) {
tags . videoHDR = "SL-HDR1" ;
} else if ( video . hdr _format . match ( /SL-HDR2/ ) !== null ) {
tags . videoHDR = "SL-HDR2" ;
}
}
if ( "writing_library" in video ) {
2021-11-29 16:42:55 +00:00
if ( video . writing _library . match ( /^x265/ ) !== null ) {
2021-11-21 03:17:10 +00:00
tags . videoEncoder = "x265" ;
2021-11-29 16:42:55 +00:00
let versionMatch = video . writing _library . match ( /^x265 (?<version>[0-9+]+(-[a-f0-9]+)?):/ )
if ( versionMatch !== null ) {
tags . videoEncoderVersion = parseInt ( versionMatch . groups . version ) ;
}
2021-11-21 03:17:10 +00:00
} else if ( video . writing _library . match ( /x264/ ) !== null ) {
tags . videoEncoder = "x264" ;
2021-11-21 15:26:00 +00:00
let versionMatch = video . writing _library . match ( / r(?<version>[0-9]+) / )
if ( versionMatch !== null ) {
tags . videoEncoderVersion = parseInt ( versionMatch . groups . version ) ;
}
2021-11-29 16:42:55 +00:00
} else if ( video . writing _library . match ( /^ATEME/ ) !== null ) {
tags . videoEncoder = "ATEME" ;
2021-11-22 09:23:11 +00:00
} else if ( video . writing _library . match ( /libaom/ ) !== null ) {
tags . videoEncoder = "libaom" ;
2021-11-21 03:17:10 +00:00
} else if ( video . writing _library . match ( /_nvenc/ ) !== null ) {
tags . videoEncoder = "NVENC" ;
2021-11-29 18:02:16 +00:00
if ( getSetting ( "warning_hwEncoder" ) ) {
warnings . video . push ( [ "danger" , "Found NVENC hardware-encoded stream" ] ) ;
}
2021-11-21 03:17:10 +00:00
} else if ( video . writing _library . match ( /_qsv/ ) !== null ) {
tags . videoEncoder = "QuickSync" ;
2021-11-29 18:02:16 +00:00
if ( getSetting ( "warning_hwEncoder" ) ) {
warnings . video . push ( [ "danger" , "Found QuickSync hardware-encoded stream" ] ) ;
}
2021-11-21 03:17:10 +00:00
} else if ( video . writing _library . match ( /_vaapi/ ) !== null ) {
tags . videoEncoder = "VAAPI" ;
2021-11-29 18:02:16 +00:00
if ( getSetting ( "warning_hwEncoder" ) ) {
warnings . video . push ( [ "danger" , "Found VAAPI hardware-encoded stream" ] ) ;
}
2021-11-21 03:17:10 +00:00
} else if ( video . writing _library . match ( /[^0-9A-F]/ ) !== null ) {
[ tags . videoEncoder ] = video . writing _library . split ( " " ) ;
}
}
2021-11-21 15:37:46 +00:00
//Detect probably H264 remuxes
try {
if (
! ( "remux" in tags ) &&
! ( "encoding_settings" in video ) && ! ( "writing_library" in video ) &&
video . codec _id === "V_MPEG4/ISO/AVC" && video . format _profile === "High@L4.1" &&
2021-11-29 16:42:55 +00:00
"format_settings" in video && video . format _settings . match ( /CABAC \/ [234] Ref Frames/ ) !== null && width === 1920 && height === 1080 &&
2021-11-21 15:37:46 +00:00
video . frame _rate _mode === "Constant" &&
( ! ( "bits_pixel_frame" in video ) || parseFloat ( video . bits _pixel _frame ) > 0.5 )
) {
tags . remux = "probably" ;
}
} catch ( e ) {
}
2021-11-29 16:42:55 +00:00
//Detect probably H265 4K remuxes
try {
if (
! ( "remux" in tags ) &&
(
//TODO: add more if found
( ! ( "encoding_settings" in video ) && ! ( "writing_library" in video ) ) ||
( ! ( "encoding_settings" in video ) && video . writing _library . match ( /^ATEME/ ) !== null ) ||
( ( ! ( "encoding_settings" in video ) || ( video . encoding _settings . match ( /crf=[0-9]+/ ) === null ) ) && video . writing _library . match ( /^x265/ ) !== null )
) &&
video . codec _id === "V_MPEGH/ISO/HEVC" && video . format _profile === "Main 10@L5.1@High" &&
width === 3840 && height === 2160 &&
video . frame _rate _mode === "Constant" &&
( ! ( "bits_pixel_frame" in video ) || parseFloat ( video . bits _pixel _frame ) > 0.2 )
) {
tags . remux = "probably" ;
}
} catch ( e ) {
}
2021-11-21 03:17:10 +00:00
if ( "encoding_settings" in video ) {
let match = null ;
if ( ( match = video . encoding _settings . match ( /crf=(?<crf>[0-9.]+)/ ) ) !== null ) {
tags . videoCRF = parseFloat ( match . groups . crf ) . toFixed ( 1 ) ;
}
if ( video . encoding _settings . match ( /rc=2pass/ ) !== null ) {
tags . videoCRF = "2pass" ;
}
2021-11-21 15:37:46 +00:00
if ( ! ( "remux" in tags ) && video . codec _id === "V_MPEG4/ISO/AVC" && ( match = video . format _profile . match ( /(?<profile>(baseline|main)[ 0-9]*)@/i ) ) !== null ) {
2021-11-29 18:02:16 +00:00
if ( getSetting ( "warning_encodeProfile" ) ) {
warnings . video . push ( [ "warning" , "Found encode using profile=" + match . groups . profile + " on encoding settings" ] ) ;
}
2021-11-21 03:17:10 +00:00
}
2021-11-29 18:02:16 +00:00
if ( video . encoding _settings . match ( /cabac=0/ ) !== null && getSetting ( "warning_encodeSettings" ) ) {
2021-11-21 03:43:15 +00:00
warnings . video . push ( [ "info" , "Found encode with CABAC disabled" ] ) ;
2021-11-21 03:17:10 +00:00
}
2021-11-29 18:02:16 +00:00
if ( video . encoding _settings . match ( /mbtree=0/ ) !== null && getSetting ( "warning_encodeSettings" ) ) {
2021-11-21 03:43:15 +00:00
warnings . video . push ( [ "info" , "Found encode with mbtree disabled" ] ) ;
2021-11-21 03:17:10 +00:00
}
2021-11-29 18:02:16 +00:00
if ( video . encoding _settings . match ( /bframes=0/ ) !== null && getSetting ( "warning_encodeSettings" ) ) {
2021-11-21 03:43:15 +00:00
warnings . video . push ( [ "info" , "Found encode with bframes disabled" ] ) ;
2021-11-21 03:17:10 +00:00
}
2021-11-29 18:02:16 +00:00
if ( video . encoding _settings . match ( /me=dia/ ) !== null && getSetting ( "warning_encodeSettings" ) ) {
2021-11-21 03:43:15 +00:00
warnings . video . push ( [ "info" , "Found encode with me=dia" ] ) ;
2021-11-21 03:17:10 +00:00
}
}
}
2021-11-25 19:53:01 +00:00
let audioLanguages = { } ;
2021-11-21 14:41:03 +00:00
mediainfo . audio . forEach ( ( audio , index ) => {
2021-11-29 16:42:55 +00:00
makeAudioObject ( audio ) ;
2021-11-21 14:41:03 +00:00
const isDefault = audio . default === "Yes" ;
if ( isDefault ) {
defaultAudio = audio ;
}
2021-11-25 19:53:01 +00:00
let audioLang = "language" in audio ? audio . language : "Unknown" ;
2021-11-29 18:02:16 +00:00
if ( audioLang !== "Japanese" && audioLang !== "Unknown" && isDefault && torrentType . match ( /Live Action/ ) === null && getSetting ( "warning_defaultAudioNotJapanese" ) ) {
2021-11-21 14:41:03 +00:00
warnings . audio . push ( [ "info" , "Default audio #" + ( index + 1 ) + " is not in Japanese" ] ) ;
}
if ( "title" in audio && audio . title . match ( /comment/i ) !== null ) {
tags . audioCommentary = true ;
2021-11-25 19:53:01 +00:00
} else {
if ( ! ( audioLang in audioLanguages ) ) {
audioLanguages [ audioLang ] = 0 ;
}
audioLanguages [ audioLang ] ++ ;
2021-11-21 14:41:03 +00:00
}
2021-11-25 19:53:01 +00:00
if ( audioLang === "Japanese" ) {
2021-11-21 14:41:03 +00:00
if ( japaneseAudio === null ) { // Pick first
japaneseAudio = audio ;
} else {
2021-11-29 16:42:55 +00:00
if ( audio . channels > japaneseAudio . channels || (
audio . channels === japaneseAudio . channels && ( // Alternate upgrade path
( [ "AAC-LC" , "HE-AAC" , "AAC-Main" , "AC3" , "Vorbis" , "MP2" , "MP3" , "DTS" ] . includes ( japaneseAudio . _ _audioCodec . name ) && [ "E-AC3" , "E-AC3 Atmos" , "DTS-HD" , "DTS-ES" ] . includes ( audio . _ _audioCodec . name ) ) ||
( ! japaneseAudio . _ _audioCodec . lossless && audio . _ _audioCodec . lossless === true )
2021-11-26 04:42:57 +00:00
)
) ) {
2021-11-21 14:41:03 +00:00
japaneseAudio = audio ;
}
}
2021-11-25 19:53:01 +00:00
} else if ( audioLang === "Unknown" ) {
2021-11-26 04:42:57 +00:00
if ( mediainfo . audio . length === 1 || ( Object . keys ( audioLanguages ) . length === 1 && "Unknown" in audioLanguages ) ) {
2021-11-21 14:41:03 +00:00
japaneseAudio = audio ;
2021-11-26 04:42:57 +00:00
} else if ( japaneseAudio !== null && ( ! ( "language" in japaneseAudio ) || japaneseAudio . language === "Unknown" ) ) {
2021-11-29 16:42:55 +00:00
if ( audio . channels > japaneseAudio . channels || (
audio . channels === japaneseAudio . channels && ( // Alternate upgrade path
( [ "AAC-LC" , "HE-AAC" , "AAC-Main" , "AC3" , "Vorbis" , "MP2" , "MP3" , "DTS" ] . includes ( japaneseAudio . _ _audioCodec . name ) && [ "E-AC3" , "E-AC3 Atmos" , "DTS-HD" , "DTS-ES" ] . includes ( audio . _ _audioCodec . name ) ) ||
( ! japaneseAudio . _ _audioCodec . lossless && audio . _ _audioCodec . lossless === true )
2021-11-26 04:42:57 +00:00
)
) ) {
japaneseAudio = audio ;
}
2021-11-21 14:41:03 +00:00
}
} else {
if ( otherAudio === null ) { // Pick first
otherAudio = audio ;
} else {
2021-11-29 16:42:55 +00:00
if ( audio . channels > otherAudio . channels ) {
2021-11-21 14:41:03 +00:00
otherAudio = audio ;
}
}
}
2021-11-25 18:53:41 +00:00
let ratio = null ;
if ( "stream_size" in audio ) {
try {
ratio = parseFloat ( audio . stream _size . match ( /\((?<percentage>[0-9.]+)%\)$/ ) . groups . percentage ) ;
} catch ( e ) {
}
}
2021-11-25 14:31:08 +00:00
2021-11-25 22:33:55 +00:00
const isRemuxOrRawSource = ( "remux" in tags || torrent . tags . container . match ( /^(ISO|M2TS|DVD)/ ) !== null ) ;
2021-11-29 18:02:16 +00:00
if ( ! isRemuxOrRawSource && audio . format === "PCM" && getSetting ( "warning_bloatPCM" ) ) {
2021-11-21 14:41:03 +00:00
warnings . audio . push ( [ "warning" , "BLOAT: Audio track #" + ( index + 1 ) + " is uncompressed PCM." ] ) ;
}
2021-11-29 18:02:16 +00:00
if ( ! isRemuxOrRawSource && ( audio . format === "FLAC" || audio . format . match ( /^DTS/ ) !== null ) && ( ratio === null || ( ratio > 10 ) ) && getSetting ( "warning_bloatg16bit" ) ) {
2021-11-21 14:41:03 +00:00
let bitDepth = parseInt ( audio . bit _depth . replace ( /[^0-9]/g , "" ) ) ;
if ( bitDepth > 16 ) {
2021-11-29 16:42:55 +00:00
warnings . audio . push ( [ "warning" , "BLOAT: Audio track #" + ( index + 1 ) + " is " + audio . _ _audioCodec . name + " with bit depth greater than 16-bit, found " + bitDepth + "-bit." ] ) ;
2021-11-21 14:41:03 +00:00
}
}
} ) ;
2021-11-25 20:03:30 +00:00
if ( Object . keys ( audioLanguages ) . length > 1 || ! ( "Unknown" in audioLanguages ) ) {
tags . audioCount = Object . keys ( audioLanguages ) . length ;
}
2021-11-21 14:41:03 +00:00
let audio = japaneseAudio !== null ? japaneseAudio : ( defaultAudio !== null ? defaultAudio : otherAudio ) ;
if ( audio !== null ) {
2021-11-29 16:42:55 +00:00
tags . audioChannels = audio . channels ;
tags . audioCodec = matchCodecEntry ( audioCodecs , audio , torrent . tags . audioCodec ) ;
2021-11-21 14:41:03 +00:00
}
if ( "text" in mediainfo ) {
mediainfo . text . forEach ( ( text ) => {
const isSignsEntry = ( "title" in text ) ? text . title . match ( /sign/i ) !== null : false ;
const isDefault = text . default === "Yes" ;
2021-11-29 18:02:16 +00:00
if ( isSignsEntry && isDefault && getSetting ( "warning_signsDefault" ) ) {
2021-11-21 14:41:03 +00:00
warnings . text . push ( [ "warning" , "Default subtitle is a Signs track" ] ) ;
}
if ( isDefault ) {
defaultSubs = text ;
}
2021-11-21 18:18:59 +00:00
if ( ! isSignsEntry && ( text . language === "English" || ( "title" in text && text . title . match ( /english/i ) !== null ) ) ) {
2021-11-21 14:41:03 +00:00
if ( englishSubs === null ) {
englishSubs = text ;
} else {
if ( text . codec _id === "S_TEXT/ASS" && englishSubs . codec _id !== "S_TEXT/ASS" ) {
englishSubs = text ;
}
}
} else if ( mediainfo . text . length === 1 && ( text . language === "Unknown" || ! ( "language" in text ) ) ) {
englishSubs = text ;
}
} ) ;
}
2021-11-21 03:17:10 +00:00
let text = englishSubs !== null ? englishSubs : ( defaultSubs !== null ? defaultSubs : ( ( "text" in mediainfo && mediainfo . text . length > 0 ) ? mediainfo . text [ 0 ] : null ) ) ;
2021-11-21 15:26:00 +00:00
let isTrackExternal = false ;
let externalTrackFormat = null ;
torrent . filelist . every ( ( file ) => {
const ext = file . path . split ( "." ) . slice ( - 1 ) [ 0 ] . toUpperCase ( ) ;
if ( ext === "ASS" || ext === "SRT" || ext === "SSA" || ext === "MKS" || ext === "VTT" || ext === "SUB" ) {
isTrackExternal = true ;
externalTrackFormat = ext ;
}
return ! isTrackExternal ;
} ) ;
2021-11-21 03:17:10 +00:00
if ( text !== null ) {
2021-11-25 22:32:46 +00:00
switch ( text . format ) {
case "EIA-608" :
tags . subtitleCodec = "CC SRT" ;
break ;
case "UTF-8" :
tags . subtitleCodec = text . codec _id === "S_TEXT/UTF8" ? "SRT" : text . format ;
break ;
case "RLE" :
tags . subtitleCodec = "VobSub" ;
break ;
default :
tags . subtitleCodec = text . format ;
}
2021-11-21 15:26:00 +00:00
tags . subtitleTitle = "title" in text ? text . title : "" ;
2021-11-21 14:58:55 +00:00
2021-11-21 15:26:00 +00:00
if ( isTrackExternal === false && torrent . tags . subtitleType === "Softsubs" && englishSubs === null ) {
2021-11-21 14:58:55 +00:00
warnings . text . push ( [ "warning" , "Could not find English labeled subtitles, but labeled Softsubs" ] ) ;
} else {
tags . subtitleType = "Softsubs" ;
}
2021-11-21 15:26:00 +00:00
}
2021-11-25 18:07:42 +00:00
if ( ( tags . subtitleType === "Softsubs" || torrent . tags . subtitleType === "Softsubs" ) && ( text === null || englishSubs === null ) ) {
2021-11-21 13:15:27 +00:00
if ( isTrackExternal ) {
tags . subtitleType = "Softsubs" ;
tags . subtitleCodec = "External " + externalTrackFormat ;
2021-11-29 18:02:16 +00:00
if ( getSetting ( "warning_externalSubs" ) ) {
warnings . text . push ( [ "info" , "Subtitle track is external" ] ) ;
}
2021-11-21 13:15:27 +00:00
} else if ( "subtitleType" in torrent . tags && torrent . tags . subtitleType !== "Hardsubs" ) {
warnings . text . push ( [ "warning" , "Could not find subtitles either on file listing or disk, probably hardsubbed?" ] ) ;
}
2021-11-21 03:17:10 +00:00
}
2021-11-21 15:26:00 +00:00
if ( "menu" in mediainfo ) {
2021-11-25 18:07:42 +00:00
//Check for chapters and ordered chapters
let chapterCount = 0 ;
2021-11-21 15:26:00 +00:00
for ( const [ key , value ] of Object . entries ( mediainfo . menu ) ) {
let entryCount = 0 ;
value . split ( " / " ) . forEach ( ( i ) => {
i = i . trim ( ) ;
if ( i . indexOf ( ":" ) !== - 1 ) {
entryCount ++ ;
}
} ) ;
2021-11-25 18:07:42 +00:00
if ( entryCount > 1 && ! ( "chapters" in tags ) ) {
tags . chapters = "ordered" ;
2021-11-29 18:02:16 +00:00
if ( getSetting ( "warning_orderedChapters" ) ) {
warnings . general . push ( [ "warning" , "Found Ordered Chapters" ] ) ;
}
2021-11-21 15:26:00 +00:00
}
2021-11-25 18:07:42 +00:00
++ chapterCount ;
2021-11-21 15:26:00 +00:00
}
2021-11-25 18:07:42 +00:00
if ( ! ( "chapters" in tags ) && chapterCount > 1 ) {
tags . chapters = chapterCount
}
}
2021-11-25 22:32:46 +00:00
matchSet . forEach ( ( entry ) => {
2021-11-26 05:38:37 +00:00
try {
let match = true ;
let set = Object . assign ( { } , entry . set ) ;
let m = null ;
for ( const [ k , v ] of Object . entries ( entry . match ) ) {
let ob = null ;
if ( k === "tags" ) {
ob = { } ;
for ( const [ key , value ] of Object . entries ( tags ) ) {
if ( ! ( key in ob ) ) {
ob [ key ] = value ;
}
2021-11-25 22:32:46 +00:00
}
2021-11-26 05:38:37 +00:00
for ( const [ key , value ] of Object . entries ( torrent . tags ) ) {
if ( ! ( key in ob ) ) {
ob [ key ] = value ;
2021-11-26 04:42:57 +00:00
}
}
2021-11-26 05:38:37 +00:00
} else if ( k === "video" ) {
ob = video ;
} else if ( k === "audio" ) {
ob = audio ;
} else if ( k === "text" ) {
ob = text ;
} else if ( k === "custom" && typeof v === 'function' ) {
m = v ( torrent , mediainfo , tags , video , audio , text ) ;
if ( m === null || m === false ) {
2021-11-25 22:32:46 +00:00
match = false ;
break ;
}
2021-11-26 05:38:37 +00:00
if ( typeof m === "object" && "groups" in m && typeof m . groups === "object" ) {
2021-11-25 22:32:46 +00:00
for ( const [ k2 , v2 ] of Object . entries ( m . groups ) ) {
if ( typeof v2 !== "undefined" ) {
for ( const [ k3 , v3 ] of Object . entries ( set ) ) {
if ( typeof v3 === 'string' ) {
set [ k3 ] = v3 . replace ( '$' + k2 , v2 ) ;
}
}
} else {
for ( const [ k3 , v3 ] of Object . entries ( set ) ) {
if ( typeof v3 === 'string' ) {
set [ k3 ] = v3 . replace ( '$' + k2 , "" ) ;
}
}
}
}
}
2021-11-26 05:38:37 +00:00
continue ;
}
if ( ob === null ) {
2021-11-25 22:32:46 +00:00
match = false ;
break ;
}
2021-11-26 05:38:37 +00:00
for ( const [ key , value ] of Object . entries ( v ) ) {
if ( value === null ) {
if ( key in ob ) {
match = false ;
break ;
}
continue ;
}
if ( ! ( key in ob ) ) {
match = false ;
break ;
} else if ( value instanceof RegExp ) {
if ( ( m = ob [ key ] . match ( value ) ) === null ) {
match = false ;
break ;
}
2021-11-25 22:32:46 +00:00
2021-11-26 05:38:37 +00:00
if ( "groups" in m && typeof m . groups === "object" ) {
for ( const [ k2 , v2 ] of Object . entries ( m . groups ) ) {
if ( typeof v2 !== "undefined" ) {
for ( const [ k3 , v3 ] of Object . entries ( set ) ) {
if ( typeof v3 === 'string' ) {
set [ k3 ] = v3 . replace ( '$' + k2 , v2 ) ;
}
}
} else {
for ( const [ k3 , v3 ] of Object . entries ( set ) ) {
if ( typeof v3 === 'string' ) {
set [ k3 ] = v3 . replace ( '$' + k2 , "" ) ;
}
}
}
}
}
} else if ( ob [ key ] !== value ) {
match = false ;
break ;
}
}
2021-11-25 22:32:46 +00:00
}
2021-11-26 05:38:37 +00:00
if ( match ) {
for ( const [ k , v ] of Object . entries ( set ) ) {
tags [ k ] = v . trim ( ) ;
}
}
} catch ( e ) {
console . log ( e ) ;
2021-11-25 22:32:46 +00:00
}
} ) ;
2021-11-25 18:07:42 +00:00
} else {
torrent . elements . item . style [ "font-style" ] = "italic" ;
2021-11-29 18:02:16 +00:00
if ( getSetting ( "warning_mediainfoInvalid" ) ) {
warnings . text . push ( [ "danger" , "No valid mediainfo section found. Report torrent with MediaInfo." ] ) ;
}
2021-11-25 18:07:42 +00:00
}
2021-11-21 15:26:00 +00:00
2021-11-21 03:17:10 +00:00
2021-11-25 18:07:42 +00:00
for ( const [ key , value ] of Object . entries ( torrent . tags ) ) {
if ( ! ( key in tags ) ) {
tags [ key ] = value ;
2021-11-21 13:15:27 +00:00
}
2021-11-25 18:07:42 +00:00
}
2021-11-21 13:15:27 +00:00
2021-11-25 18:07:42 +00:00
if ( ! ( "aspectRatio" in torrent . tags ) && "aspectRatio" in tags ) {
torrent . tags . aspectRatio = tags . aspectRatio ;
}
2021-11-21 15:26:00 +00:00
2021-11-29 16:42:55 +00:00
//console.log(tags);
2021-11-25 18:07:42 +00:00
let oldTagLine = getComparisonLine ( torrent . tags ) ;
let newTagLine = getComparisonLine ( tags ) ;
2021-11-21 15:26:00 +00:00
2021-11-29 18:02:16 +00:00
if ( newTagLine !== oldTagLine && getSetting ( "warning_tagMismatch" ) ) {
2021-11-25 18:07:42 +00:00
warnings . general . push ( [ "danger" , "Tag mismatch:\nold: " + oldTagLine + " !=\nnew: " + newTagLine ] ) ;
}
2021-11-21 15:26:00 +00:00
2021-11-25 18:07:42 +00:00
let messages = document . createElement ( "div" ) ;
messages . append ( document . createElement ( "br" ) ) ;
let h2 = document . createElement ( "h2" ) ;
h2 . textContent = "Warning Messages" ;
messages . append ( h2 ) ;
2021-11-21 15:26:00 +00:00
2021-11-25 18:07:42 +00:00
for ( const [ key , value ] of Object . entries ( warnings ) ) {
if ( value . length > 0 ) {
2021-11-21 03:17:10 +00:00
2021-11-25 18:07:42 +00:00
let h3 = document . createElement ( "h3" ) ;
h3 . textContent = key . toUpperCase ( ) ;
messages . append ( h3 ) ;
2021-11-21 03:17:10 +00:00
2021-11-25 18:07:42 +00:00
let messageList = document . createElement ( "ul" ) ;
2021-11-21 03:17:10 +00:00
2021-11-25 18:07:42 +00:00
for ( let v of value ) {
let li = document . createElement ( "li" ) ;
li . style . float = "inherit" ;
let value = "" ;
if ( Array . isArray ( v ) ) {
2021-11-21 03:17:10 +00:00
2021-11-25 18:07:42 +00:00
switch ( v [ 0 ] ) {
case "info" :
infoCount ++ ;
value = "info: " + v [ 1 ] ;
break ;
case "warning" :
warningCount ++ ;
value = "warning: " + v [ 1 ] ;
break ;
case "danger" :
dangerCount ++ ;
value = "danger: " + v [ 1 ] ;
break ;
}
} else {
++ warningCount ;
value = v ;
}
2021-11-21 03:17:10 +00:00
2021-11-25 18:07:42 +00:00
if ( value . includes ( "\n" ) ) {
let pre = document . createElement ( "pre" ) ;
pre . textContent = value ;
li . append ( pre ) ;
} else {
li . textContent = value ;
}
2021-11-21 03:43:15 +00:00
2021-11-25 18:07:42 +00:00
messageList . append ( li ) ;
}
2021-11-21 13:15:27 +00:00
2021-11-25 18:07:42 +00:00
messages . append ( messageList ) ;
messages . append ( document . createElement ( "br" ) ) ;
}
}
messages . append ( document . createElement ( "hr" ) ) ;
2021-11-21 13:15:27 +00:00
2021-11-25 18:07:42 +00:00
if ( infoCount > 0 || warningCount > 0 || dangerCount > 0 ) {
if ( "description" in torrent . elements ) {
torrent . elements . description . prepend ( messages ) ;
}
}
2021-11-21 13:15:27 +00:00
2021-11-25 18:07:42 +00:00
/ * w h i l e ( t o r r e n t . e l e m e n t s . e n t r y . f i r s t C h i l d ) {
torrent . elements . entry . firstChild . remove ( ) ;
} * /
torrent . elements . entry . parentElement . remove ( ) ;
2021-11-21 13:15:27 +00:00
2021-11-29 18:02:16 +00:00
let entries = getEntryLine ( getSetting ( "enhanceTags" ) === false ? torrent . tags : tags , infoCount , warningCount , dangerCount ) ;
2021-11-21 13:15:27 +00:00
2021-11-25 21:27:21 +00:00
let lastTd = torrent . elements . link . parentElement . parentElement ;
2021-11-21 13:15:27 +00:00
2021-11-25 18:07:42 +00:00
let onclickFn = ( e ) => {
torrent . elements . data . classList . toggle ( "hide" ) ;
e . preventDefault ( ) ;
} ;
2021-11-21 13:15:27 +00:00
2021-11-25 18:07:42 +00:00
[ "icons" , "source" , "video" , "audio" , "text" , "other" ] . forEach ( ( k ) => {
let td = document . createElement ( "td" ) ;
2021-11-25 18:53:41 +00:00
td . style [ "max-width" ] = "calc(80% / " + torrentTableColspan + ")" ;
2021-11-25 18:07:42 +00:00
if ( k !== "other" ) {
2021-11-25 19:24:56 +00:00
td . style [ "width" ] = "fit-content" ;
2021-11-25 18:07:42 +00:00
}
td . style [ "cursor" ] = "pointer" ;
2021-11-21 13:15:27 +00:00
2021-11-25 18:07:42 +00:00
let a = document . createElement ( "a" ) ;
if ( tags . snatched ) {
a . classList . add ( "snatched-torrent" ) ;
2021-11-21 03:17:10 +00:00
}
2021-11-25 18:07:42 +00:00
a . setAttribute ( "href" , torrent . elements . entry . href ) ;
2021-11-21 03:17:10 +00:00
2021-11-25 18:07:42 +00:00
a . addEventListener ( "click" , ( e ) => e . preventDefault ( ) ) ;
td . addEventListener ( "click" , onclickFn ) ;
2021-11-21 03:17:10 +00:00
2021-11-25 18:07:42 +00:00
entries [ k ] . forEach ( ( e ) => {
if ( a . firstChild ) {
a . append ( " / " ) ;
2021-11-21 03:43:15 +00:00
}
2021-11-25 18:07:42 +00:00
a . append ( e ) ;
} ) ;
2021-11-21 14:51:42 +00:00
2021-11-25 18:07:42 +00:00
td . append ( a ) ;
2021-11-21 03:17:10 +00:00
2021-11-25 18:07:42 +00:00
lastTd . insertAdjacentElement ( "afterend" , td )
lastTd = td ;
} ) ;
2021-11-21 03:17:10 +00:00
2021-11-29 18:02:16 +00:00
let regexpFilter = getSetting ( "regexpFilter" ) . trim ( ) ;
if ( regexpFilter !== "" && torrent . elements . item . textContent . match ( new RegExp ( regexpFilter ) ) !== null ) {
//Filter out, only if not directly linked
if ( ! window . location . href . includes ( "torrentid=" + torrent . id ) ) {
torrent . elements . item . style [ "display" ] = "none" ;
torrent . elements . data . style [ "display" ] = "none" ;
}
}
2021-11-21 03:17:10 +00:00
} catch ( e ) {
console . log ( "Error:" , e ) ;
console . log ( torrent ) ;
2021-11-25 20:00:23 +00:00
//Fix entries
torrent . elements . entry . parentElement . setAttribute ( "colspan" , torrentTableColspan . toString ( ) ) ;
2021-11-21 03:17:10 +00:00
}
} ) ;
2021-11-29 18:02:16 +00:00
} else if ( window . location . href . match ( /user\.php\?action=edit/ ) !== null ) {
let tabs = document . querySelector ( "ul.ue_tabs" ) ;
let sections = document . getElementById ( "tabs" ) ;
let section = document . createElement ( "div" ) ;
section . id = "mediainfo_settings" ;
let e = document . createElement ( "div" ) ;
e . classList . add ( "head" , "colhead_dark" , "strong" ) ;
e . textContent = "Mediainfo Userscript Settings" ;
section . append ( e ) ;
let ul = document . createElement ( "ul" ) ;
ul . classList . add ( "nobullet" , "ue_list" ) ;
section . append ( ul ) ;
e = document . createElement ( "div" ) ;
e . classList . add ( "head" , "colhead_dark" , "strong" ) ;
e . textContent = "Mediainfo Userscript Warnings" ;
section . append ( e ) ;
let ul _warn = document . createElement ( "ul" ) ;
ul _warn . classList . add ( "nobullet" , "ue_list" ) ;
section . append ( ul _warn ) ;
Object . values ( settings ) . forEach ( ( setting ) => {
let li = document . createElement ( "li" ) ;
let name = document . createElement ( "span" ) ;
name . classList . add ( "ue_left" , "strong" ) ;
name . textContent = setting . name ;
li . append ( name ) ;
let entry = document . createElement ( "span" ) ;
entry . classList . add ( "ue_right" ) ;
let input = document . createElement ( "input" ) ;
input . id = "mediainfo_" + setting . id ;
switch ( setting . type ) {
case "bool" :
input . setAttribute ( "type" , "checkbox" ) ;
input . checked = setting . value ;
break ;
case "string" :
input . setAttribute ( "type" , "text" ) ;
input . value = setting . value ;
break ;
case "int" :
input . setAttribute ( "type" , "number" ) ;
input . value = setting . value ;
break ;
}
const eventHandler = ( ) => {
switch ( setting . type ) {
case "bool" :
setSetting ( setting . id , input . checked ) ;
break ;
case "string" :
setSetting ( setting . id , input . value ) ;
break ;
case "int" :
setSetting ( setting . id , parseInt ( input . value ) ) ;
break ;
}
} ;
input . addEventListener ( "change" , eventHandler ) ;
input . addEventListener ( "keyup" , eventHandler ) ;
entry . append ( input ) ;
let desc = document . createElement ( "label" ) ;
desc . setAttribute ( "for" , input . id ) ;
desc . textContent = " " + setting . description ;
entry . append ( desc ) ;
li . append ( entry ) ;
if ( setting . id . match ( /^warning_/ ) !== null ) {
ul _warn . append ( li ) ;
} else {
ul . append ( li ) ;
}
} ) ;
sections . append ( section ) ;
let tab = document . createElement ( "li" ) ;
let a = document . createElement ( "a" ) ;
a . href = "#" + section . id ;
a . textContent = "Mediainfo Settings" ;
tab . append ( "•" ) ;
tab . append ( a ) ;
tabs . append ( tab ) ;
2021-11-21 03:17:10 +00:00
}