- // ==UserScript==
- // @name Better pornolab.net posts
- // @namespace Violentmonkey Scripts
- // @match *://pornolab.net/forum/viewtopic.php
- // @grant none
- // @version 2.4.1
- // @author -
- // @description Make download link easier to find and click, add a textarea with the torrent title to easily edit a copy, torrent title gets cleaned up (removal of redundant websites, useless tags, characters not allowed in file names, sort performers), add a link you can tab into from the textarea to quickly download the torrent. 2022-02-05 05:39:47
- // @run-at document-idle
- // @inject-into page
- // ==/UserScript==
-
-
- // this.$ = this.jQuery = jQuery.noConflict(true) // disabled because it prevented uncollapsing collapsed posts
- $("div#tor-reged").ready(function () {
-
- // make download link easier to find and click
- $("div#tor-reged a.dl-stub.dl-link").prepend("Download | ")
- $("div#tor-reged p").has("a.dl-stub").has("img").css("width", "100%").css("display", "block")
- $("div#tor-reged a.dl-stub").has("img").css("width", "100%").css("display", "block")
- $("div#tor-reged a.dl-stub img").css("width", "10em").css("height", "10em").css("image-rendering", "-moz-crisp-edges").css("border", "0.5em solid black").css("border-radius", "1em")
-
- // uncollapse spoilers - shows all the images
- $("div.sp-open-all.sp-open-collapsed")[0].click()
-
- // Try the following to stop smoothing in your browser:
- // image-rendering: optimizeSpeed; /* STOP SMOOTHING, GIVE ME SPEED */
- // image-rendering: -moz-crisp-edges; /* Firefox */
- // image-rendering: -o-crisp-edges; /* Opera */
- // image-rendering: -webkit-optimize-contrast; /* Chrome (and eventually Safari) */
- // image-rendering: pixelated; /* Chrome */
- // image-rendering: optimize-contrast; /* CSS3 Proposed */
- // -ms-interpolation-mode: nearest-neighbor; /* IE8+ */
-
- var title = $("h1.maintitle a").text()
- // $("h1.maintitle a").remove()
-
- function s(text, regex, replacement) {
- return text.replace(regex, replacement)
- }
-
- title = s(title, / \/ /g, ' ') // Remove slashes, not allowed in file names. Replace with spaces
- title = s(title, /\/ /g, ' ') // Remove slashes, not allowed in file names. Replace with spaces
- title = s(title, / \//g, ' ') // Remove slashes, not allowed in file names. Replace with spaces
- title = s(title, / \| /g, ' ') // Remove pipes. Replace with spaces
- title = s(title, / г\./g, '') // Russian cyrillic shorthand for the word "year"
- title = s(title, /(19[7-9][0-9])\./g, '$1') // Dot put in Russian after the year. We don't cate about scenes from before 1970...
- title = s(title, /(20[0-9][0-9])\./g, '$1') // Dot put in Russian after the year
- title = s(title, /´|`|‘|’/g, "'") // Replace unicode apostrophes with ascii apostrophe
- title = s(title, /\?/g, "?") // Replace questionmark (illegal in file names) with Unicode full-width question mark (legal in file names)
- title = s(title, /,([^ ])/g, ", $1") // Make sure there's a space after every comma
- title = s(title, /\)\[/g, ") [") // Add spaces between brackets and parentheses
- title = s(title, /\]\(/g, "] (") // Add spaces between brackets and parentheses (note the backslash before the right square bracket ] is unnecessary)
- title = s(title, /\]\[/g, "] [") // Add spaces between brackets and parentheses (note the backslash before the right square bracket ] is unnecessary)
- title = s(title, /\)\(/g, ") (") // Add spaces between brackets and parentheses
- title = s(title, /\] +\[/g, ", ") // Merge contiguous brackets separated by any amount of spaces
-
- // check for split scenes tag
- split_scenes = false
- matches_split_scenes = title.match(/\(Split Scenes\)/i)
- if (matches_split_scenes !== null) {
- split_scenes = true
- title = s(title, /\(Split Scenes\)/i, " ")
- }
- title = s(title, /\) \(/g, ", ") // Merge contiguous parentheses separated by any amount of spaces
- title = s(title, / +/g, " ") // Merge contiguous spaces
-
-
-
-
-
- // Fix dates
-
- // Fix dates: dashes to periods
- title = s(title, /(\d\d)-(\d\d)-(\d\d)/, function fix_dashes(all, one, two, three) {
- return one + "." + two + "." + three
- })
-
- // Find a four-digit year
- year = null
- year_short = null
- matches = title.match(/[^\d\.](20(\d\d))[^\d\.]/)
- if (matches !== null) {
- year = matches[1]
- year_short = matches[2]
- }
-
- function make_year_regex(year_str, surroundings) {
- if (surroundings === undefined) {
- surroundings = true
- }
- year_regex_year_at_end = "(\\d\\d)\\.(\\d\\d)\\." + year_str
- if (surroundings == true) {
- year_regex_year_at_end = "(^|[^\\d])" + year_regex_year_at_end + "($|[^\\d])"
- } else {
- year_regex_year_at_end = "()" + year_regex_year_at_end + "()" // keep the same amount of groups to make using the matches array easier
- }
- year_regex_year_at_start = year_str + "\\.(\\d\\d)\\.(\\d\\d)"
- if (surroundings == true) {
- year_regex_year_at_start = "(^|[^\\d])" + year_regex_year_at_start + "($|[^\\d])"
- } else {
- year_regex_year_at_start = "()" + year_regex_year_at_start + "()" // keep the same amount of groups to make using the matches array easier
- }
- // we want to prefer matches where the year is at the end, because that's the more common format
- year_regex = new RegExp(year_regex_year_at_end + "|" + year_regex_year_at_start)
- return year_regex
- }
-
- date_full = null
- if ((year !== null ) && (year_short !== null)) {
- // Keep old title value to check if anything changed when we lengthened the year
- old_title = (' ' + title).slice(1) // create copy
-
- // Upgrade two-digit years to four-digit years
- year_regex_short = make_year_regex(year_short)
- // note that either the first or second capture group will be == undefined
- title = s(title, year_regex_short, function upgrade_short_year(match_all, match_year_at_end_prefix, match_year_at_end_1, match_year_at_end_2, match_year_at_end_suffix, match_year_at_start_prefix, match_year_at_start_1, match_year_at_start_2, match_year_at_start_suffix) {
- if(match_year_at_end_1 && match_year_at_end_2) {
- return (match_year_at_end_prefix + match_year_at_end_1 + "." + match_year_at_end_2 + "." + year + match_year_at_end_suffix)
- }
- if(match_year_at_start_1 && match_year_at_start_2) {
- return (match_year_at_start_prefix + year + "." + match_year_at_start_1 + "." + match_year_at_start_2 + match_year_at_start_suffix)
- }
- return match_all
- })
-
- year_regex = make_year_regex(year)
- matches = title.match(year_regex)
- if (matches !== null) {
- date_with_surroundings = matches[0]
- matches2 = date_with_surroundings.match(make_year_regex(year, false))
- if(matches2 !== null) {
- date_full = matches2[0]
- }
- // Get rid of the year-only tag
- year_tag_regex = new RegExp("([^\\d])" + year + ", ")
- title = s(title, year_tag_regex, function get_rid_of_long_year_tag(match_all, match_prefix) {
- return match_prefix
- })
- }
- }
-
- if(date_full !== null) {
- // check for RD tag
- title = s(title, new RegExp("RD(:|) +" + date_full, 'g'), '')
- // check for the date alone
- // title = s(title, new RegExp(date_full, 'g'), '')
- }
-
- date_in_title = false
- // Fix stuff of the form [Foo.com] Performer - Title [Date, tag1, tag2, ...]
- // to look like [Foo.com] Performer (Title Date) [tag1, tag2, ...]
- matches = title.match(/(\[[^\]]+\] [^\[]+) - ([^\[]+) \[(\d\d\d\d\.\d\d\.\d\d|\d\d\.\d\d\.\d\d\d\d|\d\d\.\d\d\.\d\d), (.*)/)
- if (matches !== null) {
- title = matches[1] + " (" + matches[2] + " " + matches[3] + ") [" + matches[4]
- date_in_title = true
- }
-
- // Fix stuff of the form [Foo.com] Performer - Title (Date) [tag1, tag2, ...]
- // to look like [Foo.com] Performer (Title Date) [tag1, tag2, ...]
- matches = title.match(/(\[[^\]]+\] [^\[]+) - ([^\[]+) \((\d\d\d\d\.\d\d\.\d\d|\d\d\.\d\d\.\d\d\d\d|\d\d\.\d\d\.\d\d)\) \[(.*)/)
- if (matches !== null) {
- title = matches[1] + " (" + matches[2] + " " + matches[3] + ") [" + matches[4]
- date_in_title = true
- }
-
- // Parse out parts of torrent's title
- matches = title.match(/(?:\[([^\]]+)\] |)([^\[]+) \[(.*)\](.*)/)
- if (matches !== null) {
- match_websites = matches[1]
- if (match_websites === undefined) { // this happens when the torrent doesn't start with [Foo.com, Bar.com]
- match_websites = ""
- }
- match_tags = matches[3]
- match_rest = matches[4]
-
- matches2 = match_rest.match(/\(([^)]*,[^)]*)\)/) // match performers: parentheses () inside which there is at least one performer, then a comma, then at least one performer.
- match_performers = null
- match_performer_scene = null
- match_title_multiple_performers = null
- multiscene = false
- if (matches2 !== null) {
- match_performers_str = matches2[1]
- match_title_multiple_performers = matches[2]
- multiscene = true
- } else {
- match_performer_scene = matches[2]
- }
-
- if(match_websites !== "") {
- websites = match_websites.split(" ")
- } else {
- websites = []
- }
-
-
- // Canonicize websites (eg add .com)
- website_full_domains = {
- "SisLovesMe": "SisLovesMe.com",
- "TeamSkeet": "TeamSkeet.com",
- "IKnowThatGirl": "IKnowThatGirl.com",
- }
-
- function l(str) {
- return str.toLocaleLowerCase()
- }
-
- websites = websites.map(function canonicize_websites_1(website) {
- Object.keys(website_full_domains).map(function canonicize_websites_2(key) {
- if (l(key) == l(website)) {
- website = website_full_domains[key]
- }
- })
- return website
- })
-
- // Capitalize websites. capitalize() is used on a single name that might be intercalated with spaces, like "foo bar" => "Foo Bar". You have to map() to use this on an Array of names.
-
- // note: capitalize() is used for websites and also used later in tag processing
- function capitalize(s) {
- const arr = s.split(" ")
- const arr2 = arr.map(function capitalize1(word) {
- if(((word.toLocaleUpperCase() === word) && (word.length > 4)) || (word.toLocaleLowerCase() === word)) {
- // word is all caps and long, or all lower case, fix it
- return word.substring(0, 1).toLocaleUpperCase() + l(word.substring(1))
- }
- return word
- })
- return arr2.join(" ")
- }
-
- website_special_capitalization = [
- "SisLovesMe.com",
- "TeamSkeet.com",
- "IKnowThatGirl.com",
- ]
-
- websites = websites.map(function capitalize_websites(website) {
- chunks = website.split(".")
- main = capitalize(chunks[0])
- chunks[0] = main
- website = chunks.join(".")
- website_special_capitalization.map(function capitalize_websites_special(special) {
- if (l(special) == l(website)) {
- website = special
- }
- })
- return website
- })
-
- websites_redundant = websites.slice(0) // Don't change this, used by tags code later
-
- // Remove redundant websites
- website_redundancies = {
- "SisLovesMe.com": ["TeamSkeet.com"],
- "IKnowThatGirl.com": ["Mofos.com"],
- }
-
- website_redundancies_found = []
- websites.map(function remove_redundant_websites_1(website) {
- Object.keys(website_redundancies).map(function remove_redundant_websites_2(key) {
- if (l(key) == l(website)) {
- website_redundancies_found = website_redundancies_found.concat(website_redundancies[key])
- }
- })
- })
-
- website_redundancies_found = website_redundancies_found.map(x => l(x))
- websites = websites.filter(function remove_found_website_redundancies(website) {
- return ! website_redundancies_found.includes(l(website))
- })
-
- // Remove duplicate websites
-
- // note: deduplicate_list() is also used for tags, below.
- function deduplicate_list(list) {
- list2 = []
- list.map(function deduplicate_list_inner(element) {
- if (! list2.includes(element)) {
- list2.push(element)
- }
- })
- return list2
- }
- websites = deduplicate_list(websites)
-
- // Get rid of shitty tags
- const shitty_tags = [
- "1 On 1",
- "69",
- "All Sex",
- "Amateur",
- "Barefoot",
- "Bare Foot",
- "BBW",
- "Bedroom",
- "Bikini",
- "Blowjob",
- "Blow Job",
- "Boy Girl",
- "Bralette",
- "Camel Toe",
- "Casual Wear",
- "Caucasian",
- "Cinematic - Story",
- "Couch",
- "Cowgirl",
- "Crop Top",
- "Cum In Hair",
- "Cum In Mouth",
- "Cum on Ass",
- "Cum on Asshole",
- "Cum on Back",
- "Cum on Face",
- "Cum on Pussy",
- "Cum on Stomach",
- "Cum on Tits",
- "Cum Shot",
- "Cumshot Facial",
- "Cumshot",
- "Curvy",
- "Cute Little Butts",
- "Deep Throat",
- "Deepthroat",
- "Dick Play",
- "Dildo",
- "Disgusted Parenting",
- "Doggy",
- "Doggystyle",
- "Dress",
- "Facial",
- "Fetish",
- "Fingering",
- "Fingering (ass)",
- "Fingering (asshole)",
- "Fingering (pussy)",
- "Hand Job",
- "HandJob",
- "Hardcore",
- "Indoor",
- "Innie",
- "Innie Pussy",
- "Interracial",
- "Jeans",
- "Lingerie",
- "Living Room",
- "Masturbation",
- "Mature",
- "Medium Ass",
- "Medium Tits",
- "Mini Skirt",
- "Missionary",
- "Natural Tits",
- "Outie",
- "Outie Pussy",
- "Panties",
- "Piercings",
- "Pussy Licking",
- "Reality",
- "Reverse Cowgirl",
- "Roleplay",
- "Shaved Pussy",
- "Step Brother",
- "Step Bro",
- "Step Dad",
- "Step Father",
- "Swallow Cum",
- "Squirt",
- "Tank Top",
- "Tattoo",
- "Thick Top",
- "Thong",
- "Tit Play",
- "Trimmed Pussy",
- "Underwear",
- "Vibrator",
- "Wild",
- "White",
- ].map(s => l(s))
-
- match_tags = s(match_tags, /,([^\ \]])/g, function fix_tag_commas(all, suffix) {
- return ", " + suffix
- })
-
- tags = match_tags.split(", ")
- tags = tags.filter(function remove_shitty_tags(tag) {
- return ! shitty_tags.includes(l(tag))
- })
-
- // Make lower-case tags capitalized
- tags = tags.map(t => capitalize(t)) // yes, I capitalize later when desynonymizing, so what.
-
- // Desynonymize tags
- const tag_synonyms = {
- "18+ Teens": "Teens",
- "18+Teens": "Teens",
- "Analingus": "Rimjob",
- "Ass Fuck": "Anal",
- "Ass Fucking": "Anal",
- "Ass Lick": "Rimjob",
- "Ass Licking": "Rimjob",
- "Asslicking": "Rimjob",
- "Family Roleplay": "Family",
- "HD Rip": "HDRip",
- "HD-Rip": "HDRip",
- "Legal Teen": "Teen",
- "Legal Teens": "Teens",
- "Rim Job": "Rimjob",
- "Rimming": "Rimjob",
- "Rimjobs": "Rimjob",
- "Red Head": "Redhead",
- "Stepsis": "Sister",
- "Stepsister": "Sister",
- "Step Sis": "Sister",
- "Step Sister": "Sister",
- "Stepmom": "Mom",
- "Stepmother": "Mom",
- "Step Mom": "Mom",
- "Step Mother": "Mom",
- "WEB DL": "Web-DL",
- "WEB-DL": "Web-DL",
- }
- tags = tags.map(function desynonymize_tags(tag) {
- cap_tag = capitalize(tag)
- if (tag_synonyms.hasOwnProperty(cap_tag)) {
- return tag_synonyms[cap_tag]
- }
- return cap_tag
- })
-
- // Fix capitalization of some tags
- tag_special_cap = [
- "4K",
- "5K",
- "6K",
- "7K",
- "8K",
- "9K",
- "10K",
- "CFNM",
- "DAP",
- "DP",
- "DVDA",
- "FFM",
- "FMM",
- "FFMM",
- "FFFM",
- "FFFFM",
- "FFFFFM",
- "FFFFFFM",
- "HDRip",
- "MILF",
- "MILFs",
- "POV",
- "VR",
- "Web-DL",
- ]
-
- tags = tags.map(function special_tag_capitalization(tag) {
- for (var i = 0; i < tag_special_cap.length; i++) {
- if (l(tag_special_cap[i]) == l(tag)) {
- return tag_special_cap[i]
- }
- }
- return tag
- })
-
- // Add tags based on other tags
- const tag_additions = {
- "Sister": ["Incest", "Family", "Taboo"],
- "Mom": ["Incest", "Family", "Taboo"],
- "Mother": ["Incest", "Family", "Taboo"],
- "Family": ["Incest", "Family", "Taboo"],
- "Incest": ["Incest", "Family", "Taboo"],
- "4K": ["2160p"],
- "2160p": ["4K"],
- "FFM": ["Threesome"],
- "FMM": ["Threesome"],
- "Stockings": ["Lingerie"],
- }
- tags_temp = tags.slice(0) // Shallow copy
-
- tags_temp.map(function add_tags_1(tag) {
- if (tag_additions.hasOwnProperty(tag)) {
- tag_additions[tag].map(function add_tags_2(addition) {
- if (!tags.includes(addition)) {
- tags.push(addition)
- }
- })
- }
- })
-
- // Add tags based on websites
- const tag_website_additions = {
- "SisLovesMe.com": ["Sister", "Incest", "Family", "Taboo", "POV"],
- }
- websites_redundant.map(function add_tags_website_1(website) {
- if (tag_website_additions.hasOwnProperty(website)) {
- tag_website_additions[website].map(function add_tags_website_2(addition) {
- if (!tags.includes(addition)) {
- tags.push(addition)
- }
- })
- }
- })
-
- // Sort preferred performers first based on order of preference
-
- const performer_preference = ["Jennifer White", "Karlee Grey", "Alexa Nova"]
-
- if (multiscene == true) {
- new_performers_preferred = []
- new_performers_other = []
- match_performers_split = match_performers_str.split(", ")
- // find all preferred performers in the performer list
- performer_preference.map(function sort_performers_preferred(performer) {
- if(match_performers_split.includes(performer)) {
- new_performers_preferred.push(performer)
- }
- })
- // add all performers that are not preferred to the "other" list
- match_performers_split.map(function sort_performers_other(performer) {
- if(! performer_preference.includes(performer)) {
- new_performers_other.push(performer)
- }
- })
- match_performers = [].concat(new_performers_preferred, new_performers_other)
- match_performers = match_performers.map(p => capitalize(p)) // capitalize performer names
- }
-
-
-
- // Add tags based on performers
- const tag_performer_additions = {
- "Alexa Nova": ["Redhead", "Brunette", "Skinny", "Teen", "Tiny Tits", "Lookalike"],
- "Karlee Grey": ["Black Hair", "Latina", "Big Naturals", "Hairy"],
- }
- Object.keys(tag_performer_additions).map(function add_tags_performer_1(performer) {
- if (((multiscene == false) && match_performer_scene.includes(performer)) || ((multiscene == true) && match_performers.includes(performer))) {
- tag_performer_additions[performer].map(function add_tags_performer_2(addition) {
- if (!tags.includes(addition)) {
- tags.push(addition)
- }
- })
- }
- })
-
- // Deduplicate tags
- tags = deduplicate_list(tags)
-
- // Check tags for a year if no other year was found
- if (date_full == null) {
- tags = tags.filter(function extract_year_from_tags(tag) {
- if(/^(20\d\d|19[7-9]\d)$/.test(tag)) {
- date_full = tag
- return false
- }
- return true
- })
- }
-
- tag_order_start = [
- "Blonde",
- "Redhead",
- "Black Hair",
- "Brunette",
- "Latina",
- "Asian",
- "Black",
- "Ebony",
- "Skinny",
- "Petite",
- "Tiny",
- "Abs",
- "Tiny Tits",
- "Big Naturals",
- "Natural Tits",
- "Big Tits",
- "Fake Tits",
- "Big Ass",
- "Nice Ass",
- "Teen",
- "Teens",
- "Babe",
- "MILF",
- "MILFs",
- "Sister",
- "Mother",
- "Incest",
- "Family",
- "Taboo",
- "Rimjob",
- "Lookalike",
- ]
- tags_start = []
- tags_rest_1 = []
- tag_order_start.map(function split_tags_to_start_and_rest_1(start_tag) {
- if (tags.includes(start_tag)) {
- tags_start.push(start_tag)
- }
- return start_tag
- })
- tags.map(function split_tags_to_start_and_rest_2(tag) {
- if (!tags_start.includes(tag)) {
- tags_rest_1.push(tag)
- }
- return tag
- })
-
- tag_order_end = [
- "Throatpie",
- "Creampie",
- "POV",
- "HDRip",
- "Web-DL",
- "4K",
- "5K",
- "6K",
- "7K",
- "8K",
- "9K",
- "10K",
- "480p",
- "540p",
- "720p",
- "1080p",
- "2160p",
- "VR",
- ]
- tags_end = []
- tags_rest_2 = []
- tag_order_end.map(function split_tags_to_end_and_rest_1(end_tag) {
- if (tags_rest_1.includes(end_tag)) {
- tags_end.push(end_tag)
- }
- return end_tag
- })
- tags_rest_1.map(function split_tags_to_end_and_rest_2(tag) {
- if (!tags_end.includes(tag)) {
- tags_rest_2.push(tag)
- }
- return tag
- })
-
- tags = [].concat(tags_start, tags_rest_2, tags_end)
-
- // Reconstruct title from parts
- need_date = (date_full !== null) && (date_in_title == false)
- date_full_part = ""
- if (need_date) {
- date_full_part = " " + date_full
- }
- if (multiscene == false) {
- if (need_date) {
- matches = match_performer_scene.match(/\)/)
- if(matches !== null) {
- match_performer_scene = s(match_performer_scene, /\)/, date_full_part + ")")
- } else {
- match_performer_scene = match_performer_scene + " (" + date_full + ")"
- }
- }
- title = match_performer_scene + " [" + tags.join(", ") + "]"
- } else {
- match_performers_str = match_performers.join(", ")
- title = match_performers_str + " (" + match_title_multiple_performers + date_full_part + ") [" + tags.join(", ") + "]"
- if (split_scenes) {
- title = title + " (Split Scenes)"
- }
- }
- if (websites.length > 0) {
- title = "[" + websites.join(" ") + "] " + title
- }
- }
-
- // Get download link
- var dl = $("div#tor-reged a.dl-stub.dl-link").attr("href")
-
- // Add title near download link to edit and copy conveniently, and a download link to tab into
- $("div#tor-reged").prepend("<div id='better-plab-dl'><p><form><textarea style='font-size: 130%; width: calc(100% - 1em); padding: 0.5em' autocorrect='off' autocomplete='off' autocapitalize='off' spellcheck='false'>" + title + "</textarea></form></p><br/><br/><br/><br/><p><a href='" + dl + "' class='dl-stub dl-link' style='width: 100%; text-align: center; font-size: 7em'>Download Torrent File</a></p><br/><br/><br/><br/></div>")
- })