userscripts/AnimeBytes/ab-mediainfo.user.js

2411 lines
93 KiB
JavaScript
Raw Normal View History

2021-11-21 03:17:10 +00:00
// ==UserScript==
// @name AnimeBytes Mediainfo Improvements
// @author WeebDataHoarder
// @version 1.16.0
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=*
// @match https://animebytes.tv/torrents2.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
// @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==
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);
}
}
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);
}
if(currentKey === null && cleanLine.toLowerCase() !== "general"){
throw ("Invalid first key " + cleanLine.toLowerCase());
}else if (currentKey !== null && cleanLine.toLowerCase() === "general"){
throw ("Found another general entry");
}
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){
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{
throw "Invalid entry: " + cleanLine;
2021-11-21 03:17:10 +00:00
}
}else{
throw "Invalid state: " + cleanLine;
2021-11-21 03:17:10 +00:00
}
});
}catch (e){
console.log(text);
console.log(e);
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: []
};
2021-11-25 18:07:42 +00:00
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(((getSetting("debug_flagUnknownCodec") && typeof tags.videoCodec !== "object") ? "NOID-" : "") + getLineTagEntry(tags.videoCodec, false) + ("videoEncoder" in tags ? " (" + tags.videoEncoder + ("videoCRF" in tags ? " " + tags.videoCRF : "") + ")" : ""));
2021-11-25 18:07:42 +00:00
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
entries.audio.push(((getSetting("debug_flagUnknownCodec") && typeof tags.audioCodec !== "object") ? "NOID-" : "") + getLineTagEntry(tags.audioCodec, false) + " " + getAudioChannels(tags.audioChannels));
2021-11-21 03:17:10 +00:00
if(tags.audioCount > 1){
entries.audio.push(tags.audioCount === 2 ? "Dual" : "Multi (" + tags.audioCount + ")");
2021-11-21 03:17:10 +00:00
}
if("audioCommentary" in tags && tags.audioCommentary){
2021-11-25 18:07:42 +00:00
entries.audio.push("Commentary");
}
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
}
}
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-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
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.openFormat && getSetting("openFormats")){
entries.other.push("Open Format");
}
2021-11-25 18:07:42 +00:00
if(tags.snatched){
entries.other.push("Snatched");
}
if(tags.pruned){
entries.other.push("Pruned");
}
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);
}
return entries;
2021-11-21 03:17:10 +00:00
}
const allowedVideoTypes = [
"Movie",
"OVA",
"ONA",
"TV Series",
"TV Special",
"DVD Special",
"BD Special"
];
const allowedMusicTypes = [
"DVD",
"PV",
"Live",
];
2021-11-21 03:17:10 +00:00
const knownSources = [
"TV",
"DVD",
"DVD5",
"DVD9",
"Blu-ray",
"UHD Blu-ray",
"HD DVD",
"VHS",
"LD",
"Web"
];
const knownContainers = [
"AVI",
"MKV", //open
2021-11-21 03:17:10 +00:00
"MP4",
"OGM", //open
2021-11-21 03:17:10 +00:00
"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 = [
{
name: "AAC-LC",
match: {
codec_id: /^A_AAC/,
format_profile: "LC"
},
legacy: "AAC"
},
{
name: "HE-AAC",
match: {
codec_id: /^A_AAC/,
format_profile: /HE-AAC/
},
2021-11-26 09:42:15 +00:00
legacy: "AAC"
},
{
name: "HE-AAC",
match: {
codec_id: "mp4a-40-5"
},
legacy: "AAC"
},
{
name: "AAC-LC",
match: {
codec_id: /^(A_AAC-2|mp4a-40-2)$/
},
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_)?AC-?3$/
},
legacy: "AC3"
},
{
name: "Opus",
match: {
codec_id: /^(A_)?OPUS/i
},
legacy: "Opus",
open: true
},
{
name: "Vorbis",
match: {
codec_id: /^(A_)?VORBIS/i
},
legacy: "Vorbis",
open: true
},
{
name: "MP2",
match: {
codec_id: "A_MPEG/L2"
},
legacy: "MP2"
},
{
name: "MP3",
match: {
codec_id: /^(MP3|A_MPEG\/L3)$/i
},
legacy: "MP3"
},
{
name: "MP3",
match: {
format: "MPEG Audio",
format_profile: "Layer 3"
},
legacy: "MP3"
},
{
name: "ALAC",
match: {
codec_id: /^(A_)?ALAC/i
},
legacy: "ALAC",
lossless: true
},
{
name: "TTA",
match: {
codec_id: /^A_TTA/
},
legacy: "TTA",
lossless: true,
open: true
},
{
name: "WavPack",
match: {
codec_id: "A_WAVPACK4"
},
legacy: "WAV",
lossless: true,
open: true
},
{
name: "FLAC",
match: {
codec_id: /^(A_)?FLAC/i
},
legacy: "FLAC",
lossless: true,
open: true
},
{
name: "PCM",
match: {
codec_id: "A_PCM/INT/LIT"
},
legacy: "PCM",
lossless: true,
open: 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
},
{
name: "TrueHD",
match: {
codec_id: /^(A_)?TRUEHD/i,
number_of_dynamic_objects: null
},
legacy: "TrueHD",
lossless: true
},
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
},
{
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",
match: {
codec_id: "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"
},
{ //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
},
{ //Even Older way of identifying
name: "DTS-HD MA",
match: {
codec_id: /^(A_DTS|DTS ES XLL)/,
commercial_name: "DTS-HD Master Audio",
channels_original: null,
},
legacy: "DTS-HD MA",
lossless: true
2021-11-21 03:17:10 +00:00
}
];
const videoCodecs = [
{
name: "MPEG-1",
2021-11-21 03:17:10 +00:00
match: {
codec_id: "V_MPEG1",
2021-11-21 03:17:10 +00:00
},
legacy: "MPEG-1/2"
2021-11-21 03:17:10 +00:00
},
{
name: "MPEG-2",
2021-11-21 03:17:10 +00:00
match: {
codec_id: "V_MPEG2",
2021-11-21 03:17:10 +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: "VC-1 $codec",
match: {
codec_id: /^V_MS\/VFW\/FOURCC \/ (?<codec>WMV3|WMVA|WVC1)/,
bit_depth: "8 bits"
},
legacy: "VC-1"
},
{
name: "DivX 4",
match: {
codec_id: /^(V_MS\/VFW\/FOURCC \/ )?DIVX/,
},
legacy: "DivX"
},
{
name: "DivX 5",
match: {
codec_id: /^(V_MS\/VFW\/FOURCC \/ )?DX50/,
},
legacy: "DivX"
},
{
name: "DivX 5",
match: {
codec_id: /(^V_MPEG4\/ISO\/ASP|DX50)$/,
},
legacy: "DivX"
},
{
name: "XviD",
match: {
codec_id: /^V_MS\/VFW\/FOURCC \/ (XVID|mp4v)/,
},
legacy: "XviD"
},
{
name: "XviD",
match: {
codec_id: /(^V_MPEG4\/ISO\/ASP|XVID)$/,
},
legacy: "XviD"
},
2021-11-21 03:17:10 +00:00
{
name: "h264",
match: {
codec_id: /^(V_MPEG4\/ISO\/AVC|avc1|V_MS\/VFW\/FOURCC \/ H264)$/,
2021-11-21 03:17:10 +00:00
bit_depth: "8 bits",
chroma_subsampling: /^4:2:0/
},
legacy: "h264"
},
{
name: "h264 $bitDepth-bit $chroma",
2021-11-21 03:17:10 +00:00
match: {
codec_id: /^(V_MPEG4\/ISO\/AVC|avc1|V_MS\/VFW\/FOURCC \/ H264)$/,
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
},
legacy: "h264 $bitDepth-bit"
2021-11-21 03:17:10 +00:00
},
{
name: "Theora",
match: {
codec_id: "V_THEORA"
},
legacy: "Theora",
open: true,
},
{
name: "VP8 $chroma",
match: {
codec_id: "V_VP8",
bit_depth: "8 bits",
chroma_subsampling: /^(4:2:0|(?<chroma>[0-9]:[0-9]:[0-9]))/
},
legacy: "VP8",
open: true,
},
{
name: "VP8 $bitDepth-bit $chroma",
match: {
codec_id: "V_VP8",
bit_depth: /^(?<bitDepth>10|12) bits/,
chroma_subsampling: /^(4:2:0|(?<chroma>[0-9]:[0-9]:[0-9]))/
},
legacy: "VP8",
open: true,
},
2021-11-21 03:17:10 +00:00
{
name: "VP9 $chroma",
2021-11-21 03:17:10 +00:00
match: {
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
},
legacy: "VP9",
open: true,
2021-11-21 03:17:10 +00:00
},
2021-11-21 03:17:10 +00:00
{
name: "VP9 $bitDepth-bit $chroma",
2021-11-21 03:17:10 +00:00
match: {
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
},
legacy: "VP9",
open: true,
2021-11-21 03:17:10 +00:00
},
2021-11-21 03:17:10 +00:00
{
name: "AV1 $chroma",
2021-11-21 03:17:10 +00:00
match: {
codec_id: /^(V_AV1$|av01)/,
bit_depth: "8 bits",
chroma_subsampling: /^(4:2:0|(?<chroma>[0-9]:[0-9]:[0-9]))/
2021-11-21 03:17:10 +00:00
},
legacy: "AV1",
open: true,
2021-11-21 03:17:10 +00:00
},
2021-11-21 03:17:10 +00:00
{
name: "AV1 $bitDepth-bit $chroma",
2021-11-21 03:17:10 +00:00
match: {
codec_id: /^(V_AV1$|av01)/,
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
},
legacy: "AV1",
open: true,
2021-11-21 03:17:10 +00:00
},
2021-11-21 03:17:10 +00:00
{
name: "h265",
2021-11-21 03:17:10 +00:00
match: {
format: "HEVC",
bit_depth: "8 bits",
2021-11-21 03:17:10 +00:00
chroma_subsampling: /^4:2:0/
},
legacy: "h265"
2021-11-21 03:17:10 +00:00
},
2021-11-21 03:17:10 +00:00
{
name: "h265 $bitDepth-bit $chroma",
2021-11-21 03:17:10 +00:00
match: {
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)$/,
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
},
legacy: "h265 $bitDepth-bit"
2021-11-21 03:17:10 +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"
},
{
name: "FOURCC-$fourcc",
match: {
codec_id: /^V_MS\/VFW\/FOURCC \/ (?<fourcc>.{4})$/,
},
legacy: "$fourcc"
},
2021-11-21 03:17:10 +00:00
];
function makeAudioObject(ob){
const channels = parseInt(("channels" in ob ? ob.channels : ("channel_count" in ob ? ob.channel_count : "1 channel")).match(/^(?<channels>[0-9]+) channel/).groups.channels);
const codec_id = ("codec_id" in ob && ob.codec_id.match(/^[0-9]+$/) === null) ? ob.codec_id : ("codec_id_hint" in ob ? ob.codec_id_hint : ob.format);
ob.channels = channels;
ob.codec_id = codec_id;
ob.__audioCodec = matchCodecEntry(audioCodecs, ob, {
name: codec_id
});
}
const matchSet = [
{
//Hidive
match: {
tags: {
sourceName: null,
source: "Web"
},
audio: {
2021-11-25 23:14:12 +00:00
codec_id: /^A_AAC/
},
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: {
}
},
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/
},
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"
}
},
{
//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"
}
},
{
//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/
},
video: {
height: /^(480|720|(1 080)) pixels$/,
frame_rate_mode: "Constant",
writing_library: "x264 core 120 r2120 0c7dab9",
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")
},
text: {
}
},
set: {
sourceName: "Crunchyroll"
}
},
{
//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"
}
},
{
//bilibili
match: {
tags: {
sourceName: null,
source: "Web"
},
audio: {
2021-11-25 23:14:12 +00:00
codec_id: /^A_AAC/
},
video: {
frame_rate_mode: "Constant",
writing_library: /^BiliBili H264 Encoder v[0-9.\-]+$/,
encoding_settings: null
},
text: {
}
},
set: {
sourceName: "bilibili"
}
},
2021-11-29 21:56:16 +00:00
{
//Netflix?
match: {
tags: {
sourceName: null,
source: "Web"
},
audio: {
codec_id: "A_EAC3",
},
video: {
height: /^(720|(1 080)) pixels$/,
frame_rate_mode: "Constant",
bit_rate_mode: "Variable",
writing_library: /^x264 core 118$/,
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] / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=2 / b_pyramid=0 / b_adapt=2 / b_bias=0 / direct=3 / weightb=1 / open_gop=0 / weightp=2 / keyint=48 / keyint_min=(23|24|25) / scenecut=0 / intra_refresh=0 / rc_lookahead=0 / 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 / ip_ratio=1\\.40 / aq=1:1\\.00")
}
},
set: {
sourceName: "Netflix*"
}
},
{
//Netflix?
match: {
tags: {
sourceName: null,
source: "Web"
},
audio: {
2021-11-26 05:14:37 +00:00
codec_id: /^A_E?AC3$/,
},
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-29 21:56:16 +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=(48|250) / keyint_min=(23|24|25) / 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")
}
},
set: {
sourceName: "Netflix*"
}
},
{
//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) => {
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);
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:
/*if("nominal_bit_rate" in video && video.nominal_bit_rate !== "4 000 kb/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;
}
switch (eac3Track.channels){
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*"
}
},
];
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-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("handleMusicVideos", "Process Music", "Process Video formats under Music categories. Example: DVD, PV, Live", "bool", true);
2021-11-29 18:02:16 +00:00
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("openFormats", "Label Open Formats", "Entries that are composed fully of known Open Formats/Codecs will be labeled as such.", "bool", true);
2021-11-29 18:02:16 +00:00
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: Low Profile", "Warn when low encoding profile is found on encode settings.", "bool", true);
addSetting("warning_encodeSettings", "Video: Settings Information", "Show extra information messages about encode settings.", "bool", true);
2021-11-29 18:02:16 +00:00
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_textLabeling", "Text: Wrongly Labeled Subtitles", "Warn when tracks are believed not their Language labeled not English.", "bool", true);
2021-11-29 18:02:16 +00:00
addSetting("warning_externalSubs", "Text: External Subtitles", "Warn when only external subtitles are present", "bool", true);
addSetting("debug_printGroup", "Print Torrent Groups", "Outputs the torrent group result of matching and parsing on console for inspection.", "bool", false);
addSetting("debug_flagUnknownCodec", "Flag Unknown Codecs", "Flags unknown codecs that have not been matched internally.", "bool", false);
2021-11-29 18:02:16 +00:00
const torrentTypeImage = document.querySelector("a.scaledImg > img");
const torrentType = torrentTypeImage ? torrentTypeImage.getAttribute("title") : null;
const torrentTypeHeader = document.querySelector("#content .thin > h2");
const torrentTypeMusic = torrentTypeHeader ? torrentTypeHeader.textContent.split(/[()\[\]\-]/g).filter((a) => a).slice(-1)[0] : 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) ||
(getSetting("handleMusicVideos") && torrentTypeMusic !== null && allowedMusicTypes.indexOf(torrentTypeMusic) !== -1)
){
2021-11-25 18:07:42 +00:00
//Make page wider
const isMusicType = torrentTypeMusic !== null && allowedMusicTypes.indexOf(torrentTypeMusic) !== -1;
const isLiveActionType = torrentType !== null && torrentType.match(/Live Action/) !== null;
console.log("Found entry type " + (isMusicType ? torrentTypeMusic : torrentType));
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);
}
});
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) => {
const downloadLink = item.querySelector("td > span a[title^='Download']");
const linkSection = downloadLink.closest("td");
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,
freeleech: torrentEntry.querySelector("img[alt^='Freeleech!']") !== null,
remastered: torrentEntry.querySelector("img[alt^='Remastered']") !== null,
snatched: torrentEntry.textContent.match(/ - Snatched/) !== null,
pruned: torrentEntry.textContent.match(/ - Pruned!/) !== null
2021-11-21 03:17:10 +00:00
};
torrentEntry.textContent.replace("»", "").replace(/ - (Snatched|Pruned!)/g, "").split(/( \| | \/ )/).forEach((t) => {
2021-11-21 03:17:10 +00:00
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]+$/i) !== null || tagEntry.match(/^(720p|1080p|1080i|4K)$/i) !== null){
tags.resolution = tagEntry.toLowerCase();
2021-11-21 03:17:10 +00:00
}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;
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);
}
}
});
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 03:17:10 +00:00
}
}
torrentListing.push(torrent);
}
});
2021-11-25 18:07:42 +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());
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) => {
e.setAttribute("colspan", (e.getAttribute("colspan") + torrentTableColspan).toString());
2021-11-25 18:07:42 +00:00
});
}
torrentListing.forEach((torrent) => {
let parent = torrent.elements.link.closest("span:not(.download_link)");
2021-11-25 18:07:42 +00:00
let td = document.createElement("td");
let element = torrent.elements.data.querySelector("td");
element.setAttribute("colspan", (element.getAttribute("colspan") + torrentTableColspan).toString());
2021-11-25 18:07:42 +00:00
parent.closest("td").insertAdjacentElement("beforebegin", td);
2021-11-25 18:07:42 +00:00
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();
}
});
});
}
let contentStyle = document.getElementById("content").style;
contentStyle["max-width"] = "calc(100% - 50px)";
contentStyle["width"] = "fit-content";
GM_addStyle("#content{ max-width: calc(100% - 50px); width: fit-content; }");
GM_addStyle("table.torrent_table { width: fit-content; min-width: calc(950px - 240px); }");
//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); }");
const torrentTableElement = document.querySelector("div#content table.torrent_table");
const resizeCallback = () => {
2021-11-29 23:36:05 +00:00
document.querySelectorAll(isMusicType ? "#torrents2 div.main_column > table:not(.torrent_table), #torrents2 div.main_column > div" : "#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();
if(getSetting("debug_printGroup")){
console.log(torrentListing);
}
2021-11-21 03:17:10 +00:00
torrentListing.forEach((torrent) => {
try {
2021-11-25 18:07:42 +00:00
let infoCount = 0;
let warningCount = 0;
let dangerCount = 0;
let tags = {
openFormat: false,
2021-11-25 18:07:42 +00:00
};
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) => {
if(p.toUpperCase() === "NF" || p.toUpperCase() === "NETFLIX"){
2021-11-25 18:07:42 +00:00
tags.sourceName = "Netflix";
}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+";
}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";
}else if(p.toUpperCase() === "WAKANIM"){
tags.sourceName = "Wakanim";
}else if(p.toUpperCase() === "ANIMELAB"){
tags.sourceName = "AnimeLab";
}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;
}
});
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";
}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")){
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";
tags.openFormat = true;
break;
case "Ogg":
tags.container = "OGM";
tags.openFormat = true;
2021-11-21 03:17:10 +00:00
break;
case "BDAV":
tags.container = "M2TS";
break;
}
2021-11-29 18:02:16 +00:00
if(torrent.mediainfoSource !== "mediainfo" && getSetting("warning_mediainfoSource")){
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.forEach((v) => {
v.__videoCodec = matchCodecEntry(videoCodecs, v, {
name: "codec_id" in v ? v.codec_id : v.format
});
if(!("open" in v.__videoCodec) || !v.__videoCodec.open){
tags.openFormat = false;
}
if(video !== null && "default" in v && v.default === "Yes"){
2021-11-26 09:28:35 +00:00
video = v;
}
});
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){
tags.videoCodec = matchCodecEntry(videoCodecs, video, torrent.tags.videoCodec);
2021-11-21 03:17:10 +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, ""));
if(((width <= 1280 && width >= 1200) || (width <= 980 && 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");
}else if(((width <= 1920 && width >= 1820) || (width <= 1480 && 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");
}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;
}
if("display_aspect_ratio" in video){
tags.aspectRatio = video.display_aspect_ratio.replace("/", ":");
}
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){
if(video.writing_library.match(/^x265/) !== null){
2021-11-21 03:17:10 +00:00
tags.videoEncoder = "x265";
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";
let versionMatch = video.writing_library.match(/ r(?<version>[0-9]+) /)
if(versionMatch !== null){
tags.videoEncoderVersion = parseInt(versionMatch.groups.version);
}
}else if(video.writing_library.match(/^ATEME/) !== null){
tags.videoEncoder = "ATEME";
}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" &&
"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){
}
//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
}
}
}
let audioLanguages = {};
2021-11-21 14:41:03 +00:00
mediainfo.audio.forEach((audio, index) => {
makeAudioObject(audio);
if(!("open" in audio.__audioCodec) || !audio.__audioCodec.open){
tags.openFormat = false;
}
const isDescriptionEntry = ("title" in audio) ? audio.title.match(/descript/i) !== null : false;
const isCommentary = "title" in audio && audio.title.match(/comment/i) !== null;
2021-11-21 14:41:03 +00:00
const isDefault = audio.default === "Yes";
if(isDefault){
defaultAudio = audio;
}
let audioLang = "language" in audio ? audio.language : "Unknown";
if(audioLang !== "Japanese" && audioLang !== "Unknown" && isDefault && !isLiveActionType && getSetting("warning_defaultAudioNotJapanese")){
2021-11-21 14:41:03 +00:00
warnings.audio.push(["info", "Default audio #"+(index+1)+" is not in Japanese"]);
}
if(isCommentary){
2021-11-21 14:41:03 +00:00
tags.audioCommentary = true;
}else{
if(!(audioLang in audioLanguages)){
audioLanguages[audioLang] = 0;
}
audioLanguages[audioLang]++;
2021-11-21 14:41:03 +00:00
}
if(!isDescriptionEntry && !isCommentary && audioLang === "Japanese"){
2021-11-21 14:41:03 +00:00
if(japaneseAudio === null){ // Pick first
japaneseAudio = audio;
}else{
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-21 14:41:03 +00:00
japaneseAudio = audio;
}
}
}else if(!isDescriptionEntry && !isCommentary && audioLang === "Unknown"){
if(japaneseAudio === null && (mediainfo.audio.length === 1 || (Object.keys(audioLanguages).length === 1 && "Unknown" in audioLanguages))){
2021-11-21 14:41:03 +00:00
japaneseAudio = audio;
}else if(japaneseAudio !== null && (!("language" in japaneseAudio) || japaneseAudio.language === "Unknown")){
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)
)
)){
japaneseAudio = audio;
}
2021-11-21 14:41:03 +00:00
}
}else if(!isDescriptionEntry && !isCommentary){
2021-11-21 14:41:03 +00:00
if(otherAudio === null){ // Pick first
otherAudio = audio;
}else{
if(audio.channels > otherAudio.channels){
2021-11-21 14:41:03 +00:00
otherAudio = audio;
}
}
}
let ratio = null;
if("stream_size" in audio){
try{
ratio = parseFloat(audio.stream_size.match(/\((?<percentage>[0-9.]+)%\)$/).groups.percentage);
}catch (e){
}
}
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){
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
}
}
});
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);
2021-11-21 14:41:03 +00:00
if(audio !== null){
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, index) => {
const isSignsEntry = ("title" in text) ? (text.title.match(/sign/i) !== null && text.title.match(/(full|dialogue)/i) === null) : false;
2021-11-21 14:41:03 +00:00
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;
}
if(!isSignsEntry && (text.language === "English" || (englishSubs === null && "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(!isSignsEntry && mediainfo.text.length === 1 && (text.language === "Unknown" || !("language" in text))){
2021-11-21 14:41:03 +00:00
englishSubs = text;
}else if(englishSubs === null && !isSignsEntry && text.language === "Japanese" && ("title" in text && text.title.match(/(full|dialogue|english)/i) !== null)){
englishSubs = text;
if(getSetting("warning_textLabeling")){
warnings.text.push(["warning", "Subtitles track #"+(index+1)+" is labeled as Japanese, but is not Japanese"]);
}
2021-11-21 14:41:03 +00:00
}
});
}
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));
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){
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 "Subrip":
tags.subtitleCodec = "SRT";
break;
case "RLE":
tags.subtitleCodec = "VobSub";
break;
default:
tags.subtitleCodec = text.format;
}
tags.subtitleTitle = "title" in text ? text.title : "";
if(isTrackExternal === false && torrent.tags.subtitleType === "Softsubs" && englishSubs === null){
warnings.text.push(["warning", "Could not find English labeled subtitles, but labeled Softsubs"]);
}else{
if(!("subtitleType" in torrent.tags) || torrent.tags.subtitleType !== "Softsubs"){
if(getSetting("warning_textLabeling")){
warnings.text.push(["warning", "Found "+tags.subtitleCodec+" Softsubs, but labeled " + (!("subtitleType" in torrent.tags) ? "RAW" : torrent.tags.subtitleType)]);
}
}
}
}
2021-11-25 18:07:42 +00:00
if((tags.subtitleType === "Softsubs" || torrent.tags.subtitleType === "Softsubs") && (text === null || englishSubs === null)){
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"]);
}
}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
}
if("menu" in mediainfo){
2021-11-25 18:07:42 +00:00
//Check for chapters and ordered chapters
let chapterCount = 0;
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-25 18:07:42 +00:00
++chapterCount;
}
2021-11-25 18:07:42 +00:00
if(!("chapters" in tags) && chapterCount > 1){
tags.chapters = chapterCount
}
}
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-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 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){
match = false;
break;
}
2021-11-26 05:38:37 +00:00
if(typeof m === "object" && "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, "");
}
}
}
}
}
2021-11-26 05:38:37 +00:00
continue;
}
if(ob === null){
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-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-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 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 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-25 18:07:42 +00:00
}
2021-11-25 18:07:42 +00:00
if(!("aspectRatio" in torrent.tags) && "aspectRatio" in tags){
torrent.tags.aspectRatio = tags.aspectRatio;
}
//console.log(tags);
2021-11-25 18:07:42 +00:00
let oldTagLine = getComparisonLine(torrent.tags);
let newTagLine = getComparisonLine(tags);
if(newTagLine.toLowerCase() !== oldTagLine.toLowerCase() && getSetting("warning_tagMismatch")){
2021-11-25 18:07:42 +00:00
warnings.general.push(["danger", "Tag mismatch:\nold: " + oldTagLine + " !=\nnew: " + newTagLine]);
}
2021-11-25 18:07:42 +00:00
let messages = document.createElement("div");
messages.append(document.createElement("br"));
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";
2021-11-25 18:07:42 +00:00
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-25 18:07:42 +00:00
messages.append(messageList);
messages.append(document.createElement("br"));
}
}
messages.append(document.createElement("hr"));
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-25 18:07:42 +00:00
/*while(torrent.elements.entry.firstChild){
torrent.elements.entry.firstChild.remove();
}*/
torrent.elements.entry.parentElement.remove();
2021-11-29 18:02:16 +00:00
let entries = getEntryLine(getSetting("enhanceTags") === false ? torrent.tags : tags, infoCount, warningCount, dangerCount);
let lastTd = torrent.elements.link.closest("td");
2021-11-25 18:07:42 +00:00
let onclickFn = (e) => {
torrent.elements.data.classList.toggle("hide");
e.preventDefault();
};
2021-11-29 21:38:12 +00:00
let entryText = [];
2021-11-25 18:07:42 +00:00
["icons", "source", "video", "audio", "text", "other"].forEach((k) => {
let td = document.createElement("td");
td.style["max-width"] = "calc(80% / " + torrentTableColspan + ")";
2021-11-25 18:07:42 +00:00
if(k !== "other"){
td.style["width"] = "fit-content";
2021-11-25 18:07:42 +00:00
}
td.style["cursor"] = "pointer";
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-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-29 21:38:12 +00:00
entryText.push(td.textContent.trim());
2021-11-25 18:07:42 +00:00
});
2021-11-21 03:17:10 +00:00
2021-11-29 18:02:16 +00:00
let regexpFilter = getSetting("regexpFilter").trim();
2021-11-29 21:38:12 +00:00
if(regexpFilter !== "" && entryText.join(" | ").match(new RegExp(regexpFilter)) !== null){
2021-11-29 18:02:16 +00:00
//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);
//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 Messages";
2021-11-29 18:02:16 +00:00
section.append(e);
let ul_warn = document.createElement("ul");
ul_warn.classList.add("nobullet", "ue_list");
section.append(ul_warn);
e = document.createElement("div");
e.classList.add("head", "colhead_dark", "strong");
e.textContent = "Mediainfo Userscript Debugging";
section.append(e);
let ul_debug = document.createElement("ul");
ul_debug.classList.add("nobullet", "ue_list");
section.append(ul_debug);
2021-11-29 18:02:16 +00:00
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 if(setting.id.match(/^debug_/) !== null){
ul_debug.append(li);
2021-11-29 18:02:16 +00:00
}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
}