├── README.md └── script.user.js /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Blackpearl OMDB Template Generator 3 | OMDB Thread Template Generator userscript 4 | 5 | ![](https://i.imgur.com/bBeusE2.png) 6 | 7 | ## Requirements: 8 | A userscript manager + installing the script 9 | Click to install script 10 | (A userscript engine, like [Violentmonkey](https://violentmonkey.github.io/get-it/) or [Tampermonkey](https://www.tampermonkey.net/)) 11 | 12 | # How To Use 13 | 14 | ### 1. 15 | First you'll want to navigate to the one of the Movie or TV Show sections and start to post a thread. 16 | 17 | ### 2. 18 | There are two ways of using the IMDB field. You can start typing the name of the Movie or Show and this will present you with a list to choose from. Simply click the correct one and move to the next step. If you are having trouble finding the movie you want I recommend using the IMDB ID method below. 19 | 20 | The other method is using the IMDB ID. This starts with "tt" and has numbers after it. For example Avengers: Endgame (2019) https://www.imdb.com/title/tt4154796/ the IMDB ID would be tt4154796. So I would enter tt4154796 into the field and go to the next step. 21 | You may also paste the link itself into the IMDB field. For example: https://www.imdb.com/title/tt4154796/ then I would continue to the next step. 22 | 23 | 24 | ### 3. 25 | Next if you have screenshots of the specific release you're posting. Enter them here with a space inbetween each link. 26 | 27 | For example: 28 | `imgur.com/image.png imgur.com/image2.png imgur.com/image3.png` 29 | 30 | ### 4. 31 | Next, you'll want to grab the offical trailer of the movie from youtube. Usually Googling the movie name and year will give you the trailer. Paste the Youtube Link into the "Youtube Trailer" Field. 32 | 33 | ### 5. 34 | Enter your download link. Be sure it's one of the accepted file hosts. You can see all the allowed filehosts [HERE](https://blackpearl.biz/faq/#q-which-file-hosters-are-accepted-on-the-forum) 35 | 36 | To enter multiple download links, ensure there is a space between each of the links. 37 | 38 | For example: 39 | `downloadlink1 downloadlink2 downloadlink3` 40 | ### 6. 41 | Enter your mediainfo. You can get mediainfo locally using [MediaInfo](https://mediaarea.net/en/MediaInfo/Download)(Use View>Text to make life easier) or through a Remote. There are two ways of getting mediainfo remotely. One is at the bottom of [This Post](https://blackpearl.biz/threads/6085/) using Google Colab. The other is using an online tool such as this [Heroku App](https://overbits.herokuapp.com/mediainfo). 42 | 43 | ### 7. 44 | The Downcloud button is clickable(Either on or off). The only reason you would need to turn it off is if you are posting multiple links or using a [Base64 Encoded String](https://www.base64encode.org/). HideReactScore has a maximum limit of 100 and minimum of 0 (0 will not add it). 45 | HidePosts has a maximum limit of 50 and minimum of 0(0 will not add it) You can find more about what each of these do [HERE](https://blackpearl.biz/help/bb-codes/). 46 | 47 | ### 8. 48 | Once you have set everything up, be sure that you are in BBCode Mode ![](https://i.imgur.com/oX1AzQ4.png) and press the "Generate Template" button and the post will be copied to your clipboard and pasted onto the site. The Title will be filled out with the Name of the Movie or Show and the Year of release. You will have to add all the other required information yourself. 49 | If you have not selected anything for the IMDB field (Either clicked on a name or entered a proper TT ID number) You will be prompted with an alert box telling you so. 50 | -------------------------------------------------------------------------------- /script.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Blackpearl Movie/TV Template Generator 3 | // @version 4.0.3 4 | // @description Template Maker 5 | // @author Blackpearl_Team 6 | // @icon https://blackpearl.biz/favicon.png 7 | // @homepage https://github.com/BlackPearl-Forum/Blackpearl-Template-Posters/ 8 | // @supportURL https://github.com/BlackPearl-Forum/Blackpearl-Template-Posters/issues/ 9 | // @updateURL https://github.com/BlackPearl-Forum/Blackpearl-Template-Posters/raw/Omdb/script.user.js 10 | // @downloadURL https://github.com/BlackPearl-Forum/Blackpearl-Template-Posters/raw/Omdb/script.user.js 11 | // @include /^https:\/\/blackpearl\.biz\/forums\/(129|172|173|174|175|176|178|179|180|181|183|184|187|188|189|190|193|194|197|198|199|200|203|204|206|207|208|210|223)\/post-thread/ 12 | // @grant GM.xmlHttpRequest 13 | // @run-at document-end 14 | // @connect imdb.com 15 | // ==/UserScript== 16 | 17 | /////////////////////////////////////////////////////////////////////////// 18 | // HTML // 19 | /////////////////////////////////////////////////////////////////////////// 20 | 21 | const htmlTemplate = ` 22 | 23 | 24 |
25 | 26 | 30 | 31 | 32 | 33 | 34 |
 
35 | DownCloud 36 | 39 | HideReactScore 40 | 41 | HidePosts 42 |
43 |
 
44 | 45 | 46 | 47 |
48 | `; 49 | 50 | const omdbinput = ` 51 | 52 | 53 |
54 | 55 |
 
56 | 57 | 58 | 59 |
60 | `; 61 | 62 | var errPopup = `
63 |
64 | 65 | Oops! We ran into some problems.
66 |
67 |
68 |
    69 | errormessages 70 |
71 |
`; 72 | 73 | var tagSelect = `
  • ×tagname
  • `; 74 | 75 | /////////////////////////////////////////////////////////////////////////// 76 | // IMDB Scraper // 77 | /////////////////////////////////////////////////////////////////////////// 78 | class Imdb { 79 | regexSplit = /([a-z])([A-Z])/g; 80 | 81 | async requestUrl(imdb) { 82 | this.imdbID = imdb?.match(/tt\d+/)[0] || null; 83 | if (!this.imdbID) { 84 | this.imdbDocument = { Error: 'Unable To Find IMDB TT ID' }; 85 | return; 86 | } 87 | this.imdbURL = 'https://imdb.com/title/' + this.imdbID; 88 | const req = await RequestUrl('GET', this.imdbURL, null, { 89 | 'accept-language': 'en-US,en', 90 | }); 91 | const parser = new DOMParser(); 92 | this.imdbDocument = parser.parseFromString(req.response, 'text/html'); 93 | } 94 | 95 | createJSON() { 96 | return { 97 | Title: this.title, 98 | Name: this.name, 99 | Poster: this.poster, 100 | Ratings: { 101 | Star: this.starRating, 102 | Total: this.totalRatings, 103 | Metascore: this.metascore, 104 | }, 105 | Plot: this.plot, 106 | Genres: this.genres, 107 | Taglines: this.taglines, 108 | ContentRating: this.mpaa, 109 | DidYouKnow: this.didYouKnow, 110 | Details: this.details, 111 | TechSpecs: this.techSpecs, 112 | Staff: this.staff, 113 | Trailer: this.trailer, 114 | Url: this.imdbURL, 115 | ID: this.imdbID, 116 | }; 117 | } 118 | get title() { 119 | return ( 120 | this.imdbDocument 121 | .querySelector('title') 122 | ?.innerText.replace(' - IMDb', '') 123 | .replace('TV Series ', '') || null 124 | ); 125 | } 126 | get name() { 127 | return ( 128 | this.imdbDocument.querySelector('[data-testid=hero-title-block__title]') 129 | ?.innerText || null 130 | ); 131 | } 132 | 133 | get poster() { 134 | return ( 135 | this.imdbDocument 136 | .querySelector('.ipc-image') 137 | ?.src?.replace(/(?!=\.)_V1_.*(?=\.jpg)/, '_V1_SX1000') || null 138 | ); 139 | } 140 | 141 | get starRating() { 142 | return ( 143 | this.imdbDocument.querySelector( 144 | '[data-testid=hero-rating-bar__aggregate-rating__score]' 145 | )?.innerText || null 146 | ); 147 | } 148 | 149 | get totalRatings() { 150 | return ( 151 | this.imdbDocument.querySelector( 152 | '[data-testid=hero-rating-bar__aggregate-rating__score]' 153 | )?.nextElementSibling?.nextElementSibling?.innerText || null 154 | ); 155 | } 156 | 157 | get plot() { 158 | return ( 159 | this.imdbDocument 160 | .querySelector('[class="ipc-html-content ipc-html-content--base"]') 161 | ?.innerText.split('—')[0] || null 162 | ); 163 | } 164 | 165 | get genres() { 166 | return ( 167 | this.imdbDocument 168 | .querySelector('[data-testid="storyline-genres"]') 169 | ?.innerText.replace(this.regexSplit, '$1,$2') 170 | ?.split(',') 171 | ?.slice(1, -1) || null 172 | ); 173 | } 174 | 175 | get taglines() { 176 | return ( 177 | this.imdbDocument.querySelector( 178 | '[data-testid="storyline-taglines"] .ipc-metadata-list-item__list-content-item' 179 | )?.innerText || null 180 | ); 181 | } 182 | 183 | get mpaa() { 184 | return ( 185 | this.imdbDocument 186 | .querySelector( 187 | '[data-testid="storyline-certificate"] .ipc-metadata-list-item__list-content-item' 188 | ) 189 | ?.innerText?.split(' ')[1] || null 190 | ); 191 | } 192 | 193 | get didYouKnow() { 194 | const nodes = 195 | this.imdbDocument 196 | .querySelector('[data-testid="DidYouKnow"]') 197 | ?.querySelectorAll('.ipc-list-card--border-line') || null; 198 | if (!nodes) { 199 | return null; 200 | } 201 | var didYouKnow = {}; 202 | for (const node of nodes) { 203 | const section = 204 | node.querySelector('.ipc-metadata-list-item__label')?.innerText || null; 205 | let content = node.querySelector('.ipc-html-content'); 206 | didYouKnow[titleCase(section).replace(/ /g, '')] = 207 | section != 'Soundtracks' 208 | ? content?.innerText || null 209 | : [...content?.children[0]?.children].map((item) => { 210 | return section == 'Official sites' ? item.href : item.innerText; 211 | }); 212 | } 213 | return didYouKnow; 214 | } 215 | 216 | get details() { 217 | const nodes = 218 | this.imdbDocument.querySelector('[data-testid="title-details-section"]') 219 | ?.children[0]?.children || null; 220 | if (!nodes || nodes.length === 0) { 221 | return null; 222 | } 223 | var details = {}; 224 | for (let node of nodes) { 225 | const section = 226 | node.querySelector('.ipc-metadata-list-item__label')?.innerText || null; 227 | let content = node.querySelectorAll( 228 | '.ipc-metadata-list-item__list-content-item' 229 | ); 230 | if (!section || section.length === 0 || content.length === 0) { 231 | continue; 232 | } 233 | details[titleCase(section).replace(/ /g, '')] = [...content].map( 234 | (item) => { 235 | return section == 'Official sites' ? item.href : item.innerText; 236 | } 237 | ); 238 | } 239 | return details; 240 | } 241 | 242 | get techSpecs() { 243 | const nodes = this.imdbDocument?.querySelectorAll( 244 | '[data-testid="TechSpecs"] .ipc-metadata-list__item' 245 | ); 246 | if (nodes.length === 0) { 247 | return null; 248 | } 249 | var specs = {}; 250 | for (const node of nodes) { 251 | const sectionNode = node?.children[0]?.innerText || null; 252 | let content = node?.children[1] || null; 253 | if (!sectionNode || !content || content.length === 0) { 254 | continue; 255 | } 256 | specs[titleCase(sectionNode).replace(/ /g, '')] = 257 | content?.children.length === 0 258 | ? content.innerText 259 | : [...content.querySelectorAll('.ipc-inline-list__item')].map( 260 | (item) => { 261 | return item.innerText; 262 | } 263 | ); 264 | } 265 | return specs; 266 | } 267 | 268 | get metascore() { 269 | return ( 270 | this.imdbDocument?.querySelector('span.score-meta')?.innerText || null 271 | ); 272 | } 273 | 274 | get staff() { 275 | const nodes = 276 | this.imdbDocument.querySelector('[data-testid="title-pc-wide-screen"]') 277 | ?.children[0]?.children || null; 278 | if (nodes?.length == 0) { 279 | return null; 280 | } 281 | var staff = {}; 282 | for (const node of nodes) { 283 | const jobTitle = 284 | node?.querySelector('.ipc-metadata-list-item__label')?.innerText || 285 | null; 286 | let people = 287 | node?.querySelectorAll('.ipc-metadata-list-item__list-content-item') || 288 | null; 289 | if (!jobTitle || !people) { 290 | continue; 291 | } 292 | staff[titleCase(jobTitle).replace(/ /g, '')] = [...people].map((item) => { 293 | return item.innerText; 294 | }); 295 | } 296 | return staff; 297 | } 298 | get trailer() { 299 | let video = 300 | this.imdbDocument.querySelector('[aria-label="Watch {VideoTitle}"]') 301 | ?.href || null; 302 | if (video) { 303 | video = video.replace(/.*(?=\/video)/, 'https://imdb.com'); 304 | } 305 | return video; 306 | } 307 | } 308 | 309 | /////////////////////////////////////////////////////////////////////////// 310 | // Utility // 311 | /////////////////////////////////////////////////////////////////////////// 312 | 313 | /** 314 | * Converts the text in a string to TitleCase 315 | * @param {string} str text to convert 316 | * @returns {string} TitleCased string 317 | */ 318 | const titleCase = (str) => { 319 | if (!str) { 320 | return str; 321 | } 322 | str = str.toLowerCase().split(' '); 323 | for (var i = 0; i < str.length; i++) { 324 | str[i] = str[i].charAt(0).toUpperCase() + str[i].slice(1); 325 | } 326 | return str.join(' '); 327 | }; 328 | 329 | /** 330 | * Converts the text in a string to pascal case (Title Case) 331 | * @param {string} word text to convert. 332 | * @returns {string} TitleCase -> Title Case 333 | */ 334 | const splitPascalCase = (word) => { 335 | return word.match(/($[a-z])|[A-Z][^A-Z]+/g).join(' '); 336 | }; 337 | 338 | // Close Error Popup if overlay clicked 339 | document.addEventListener('click', (element) => { 340 | if ( 341 | (document.querySelector('#errBox') != element.target && 342 | document.querySelector('#js-XFUniqueId2') == element.target) || 343 | document.querySelector('.js-overlayClose') == element.target 344 | ) { 345 | document.querySelector('[name="errorpopup"]').remove(); 346 | } 347 | }); 348 | 349 | /** 350 | * Changes template to "shown" state 351 | */ 352 | const ShowTemplate = () => { 353 | document.getElementById('showTemplate').style.display = 'none'; 354 | document.getElementsByName('showDivider')[0].style.display = 'none'; 355 | document.getElementById('OmdbGenerator').style.display = 'block'; 356 | }; 357 | 358 | /** 359 | * Changes template to "hidden" state 360 | */ 361 | const HideTemplate = () => { 362 | document.getElementById('showTemplate').style.display = 'block'; 363 | document.getElementsByName('showDivider')[0].style.display = 'block'; 364 | document.getElementById('OmdbGenerator').style.display = 'none'; 365 | }; 366 | 367 | /** 368 | * Pop's up an error overlay 369 | * @param {string} errors HTML Errors (li) that should be displayed to the user. 370 | * @returns {void} 371 | */ 372 | const Popup = (errors) => { 373 | let errOutput = errPopup.replace('errormessages', errors); 374 | var body = document.getElementsByTagName('Body')[0]; 375 | body.insertAdjacentHTML('beforeend', errOutput); 376 | }; 377 | 378 | /** 379 | * Adds a tag to the post. 380 | * @param {string} tag text to add to the post as a tag. 381 | * @returns {void} 382 | */ 383 | const TagsPush = (tag) => { 384 | const tagOutput = tagSelect.replace(/tagname/g, tag); 385 | let tagParent = document.getElementsByClassName( 386 | 'select2-selection__rendered' 387 | )[1]; 388 | let tagParent2 = document.getElementsByName('tokens_select')[0]; 389 | let option = document.createElement('option'); 390 | option.text = tag; 391 | option.value = tag; 392 | tagParent.insertAdjacentHTML('afterbegin', tagOutput); 393 | tagParent2.add(option); 394 | }; 395 | 396 | /** 397 | * Removes all children from a Node. 398 | * @param {HTMLElement} parent parent node to remove children from. 399 | * @returns {void} 400 | */ 401 | const RemoveAllChildNodes = (parent) => { 402 | while (parent.firstChild) { 403 | parent.removeChild(parent.firstChild); 404 | } 405 | }; 406 | 407 | /** 408 | * Asyncronous XHR returning a Promise. 409 | * @param {string} method HTTP method to use. [GET, HEAD, POST, etc] 410 | * @param {string} url String containing URL where the request should be sent. 411 | * @param {any} data Any data to be sent with your request. 412 | * @param {object} headers Object containing key and values to used as your header. 413 | * @returns {Promise} HTTP Response 414 | */ 415 | const RequestUrl = async (method, url, data, headers) => { 416 | return new Promise((resolve, reject) => { 417 | GM.xmlHttpRequest({ 418 | method: method, 419 | url: url, 420 | data: data, 421 | headers: headers, 422 | onload: (response) => { 423 | resolve(response); 424 | }, 425 | onerror: (response) => { 426 | reject(response); 427 | }, 428 | }); 429 | }); 430 | }; 431 | 432 | /** 433 | * Adds CSS into DOM. 434 | * @param {string} styleString Style to inject into HTML head 435 | */ 436 | const addStyle = (styleString) => { 437 | const style = document.createElement('style'); 438 | style.textContent = styleString; 439 | style.id = 'blackpearl-omdb-userscript'; 440 | document.head.append(style); 441 | }; 442 | 443 | /////////////////////////////////////////////////////////////////////////// 444 | // Mediainfo // 445 | /////////////////////////////////////////////////////////////////////////// 446 | /** 447 | * Handles scraping of Mediainfo 448 | * @param {string} mediainfo FULL mediainfo text from Mediainfo Application 449 | */ 450 | class Mediainfo { 451 | constructor(mediainfo) { 452 | this.video = mediainfo.match(/(Video|Video #1)$.*?(?=\n{2,})/ms)?.[0]; 453 | this.audio = mediainfo.match(/(Audio|Audio #1)$.*?(?=\n{2,})/ms)?.[0]; 454 | this.general = mediainfo.match(/General$.*?(?=\n{2,})/ms)?.[0]; 455 | } 456 | 457 | create() { 458 | return { 459 | video: this.video, 460 | audio: this.audio, 461 | general: this.general, 462 | VideoResolution: this.videoResolution, 463 | VideoLibrary: this.videoWritingLib, 464 | BitDepth: this.videoBitDepth, 465 | AudioCodec: this.audioCodec, 466 | Size: this.fileSize, 467 | }; 468 | } 469 | /** 470 | * Returns String of the corresponding resolution based on Video Width. 471 | * 472 | * Returns Empty String if Invalid or Unknown 473 | */ 474 | get videoResolution() { 475 | switch (this.video?.match(/(?<=Width.*)\d(\s)?\d+/)?.[0]) { 476 | case '3 840': 477 | return '2160p'; 478 | case '1 920': 479 | return '1080p'; 480 | case '1 280': 481 | return '720p'; 482 | case '720': 483 | return '480p'; 484 | default: 485 | return ''; 486 | } 487 | } 488 | 489 | /** 490 | * Returns String containing first video Libaray or Format 491 | * 492 | * Returns Empty String if Invalid or Unknown 493 | */ 494 | get videoWritingLib() { 495 | return ( 496 | this.video?.match(/Writing library.*(x264|x265)/)?.[1] || 497 | this.video?.match(/(?<=Format.*\s)\w{3,4}\n/)?.[0] || 498 | '' 499 | ); 500 | } 501 | 502 | /** 503 | * Returns String containing first video Bit Depth 504 | * 505 | * Returns Empty String if Invalid or Unknown 506 | */ 507 | get videoBitDepth() { 508 | return this.video?.match(/(?<=Bit depth.*)\d+/)?.[0].concat('Bit') || ''; 509 | } 510 | 511 | /** 512 | * Returns String containing first audio Codec 513 | * 514 | * Returns Empty String if Invalid or Unknown 515 | */ 516 | get audioCodec() { 517 | return this.audio?.match(/(?<=Codec ID.*A_)\w+/)?.[0] || ''; 518 | } 519 | 520 | /** 521 | * Returns String containing the File Size. 522 | * 523 | * Returns Empty String if Invalid or Unknown 524 | */ 525 | get fileSize() { 526 | return ( 527 | this.general?.match(/(?<=File size.*)\d+\s\w+/)?.[0].replace('i', '') || 528 | '' 529 | ); 530 | } 531 | } 532 | 533 | /////////////////////////////////////////////////////////////////////////// 534 | // BBCode // 535 | /////////////////////////////////////////////////////////////////////////// 536 | 537 | /** 538 | * Handles all generation of BBCode 539 | */ 540 | class BBCodeGenerator { 541 | /** 542 | * Generates BBCode for Download Links. 543 | * @param {string} links - Link(s) to be processed. 544 | * @returns {string} - Compiled BBCode. 545 | */ 546 | download(links) { 547 | links = document.getElementById('Downcloud').checked 548 | ? links.split(' ').map((link) => `[downcloud]${link}[/downcloud]\n`) 549 | : links.split(' '); 550 | var prefix = [ 551 | '[hr][/hr][center][size=6][forumcolor][b]Download Link[/b][/forumcolor][/size]\n[hidereact=1,2,3,4,5,6,7,8]', 552 | ]; 553 | var suffix = ['\n[/center]', '[/hidereact]']; 554 | const reactCount = document.getElementById('HideReactScore').value; 555 | if (reactCount !== '0') { 556 | prefix.push(`[hidereactscore=${reactCount}]`); 557 | suffix.unshift('[/hidereactscore]'); 558 | } 559 | const postsCount = document.getElementById('HidePosts').value; 560 | if (postsCount !== '0') { 561 | prefix.push(`[hideposts=${postsCount}]`); 562 | suffix.unshift('[/hideposts]'); 563 | } 564 | return prefix.join('') + links.join('') + suffix.join(''); 565 | } 566 | /** 567 | * Generates BBCode for Screenshot Images. 568 | * @param {string} links - Link(s) to be processed. 569 | * @returns {string} - Compiled BBCode 570 | */ 571 | screenshots(links) { 572 | if (!links) return ''; 573 | const imageBBCode = links 574 | .split(' ') 575 | .map((link) => `[img]${link}[/img]`) 576 | .join(''); 577 | return `\n[hr][/hr][indent][size=6][forumcolor][b]Screenshots[/b][/forumcolor][/size][/indent]\n [spoiler='Screenshots']\n${imageBBCode}[/spoiler]`; 578 | } 579 | /** 580 | * Generates BBCode based on IMDB Scraper. 581 | * @param {string} link - IMDB ID or Link. 582 | * @returns {object} - Compiled BBCode 583 | */ 584 | async imdb(link) { 585 | const scraper = new Imdb(); 586 | await scraper.requestUrl(link); 587 | if (scraper.imdbDocument?.Error) { 588 | return null; 589 | } 590 | const imdbInfo = scraper.createJSON(); 591 | // Update to show all ratings avaliable 592 | let movieInfo = ''; 593 | if (imdbInfo?.Staff) { 594 | movieInfo += Object.entries(imdbInfo.Staff) 595 | .map( 596 | (staff) => 597 | `[*][B]${splitPascalCase(staff[0])}: [/B] ${staff[1].join(', ')}\n` 598 | ) 599 | .join(''); 600 | } 601 | if (imdbInfo?.ContentRating) { 602 | movieInfo += `[*][B]Content Rating: [/B] ${imdbInfo.ContentRating}\n`; 603 | } 604 | if (imdbInfo?.Genres) { 605 | movieInfo += `[*][B]Genre: [/B] ${imdbInfo.Genres.join(', ')}\n`; 606 | } 607 | if (imdbInfo?.Details?.ReleaseDate) { 608 | movieInfo += `[*][B]Release Date: [/B] ${imdbInfo.Details.ReleaseDate.join( 609 | ', ' 610 | )}\n`; 611 | } 612 | if (imdbInfo?.TechSpecs) { 613 | movieInfo += Object.entries(imdbInfo.TechSpecs) 614 | .map( 615 | (detail) => 616 | `[*][B]${splitPascalCase(detail[0])}: [/B] ${ 617 | Array.isArray(detail[1]) ? detail[1]?.join(', ') : detail[1] 618 | }\n` 619 | ) 620 | .join(''); 621 | } 622 | if (imdbInfo?.Details?.ProductionCompanies) { 623 | movieInfo += `[*][B]Production: [/B] ${imdbInfo.Details.ProductionCompanies.join( 624 | ', ' 625 | )}\n`; 626 | } 627 | movieInfo = movieInfo 628 | ? `\n[hr][/hr][indent][size=6][forumcolor][b]Movie Info[/b][/forumcolor][/size][/indent]\n[LIST]${movieInfo}[/LIST]\n` 629 | : ''; 630 | return { 631 | Poster: imdbInfo?.Poster 632 | ? `[center][img width='350px']${imdbInfo.Poster}[/img][/center]\n` 633 | : '', 634 | Title: `[center][forumcolor][b][size=6][url='https://blackpearl.biz/search/1/?q=${ 635 | imdbInfo?.ID || '' 636 | }&o=date']${ 637 | imdbInfo?.Title || '' 638 | }[/url][/size][/b][/forumcolor][/center]\n`, 639 | Rating: imdbInfo?.Ratings?.Star 640 | ? `[size=6]${imdbInfo.Ratings.Star}[/size][/center]\n` 641 | : '[/center]\n', 642 | TotalRatings: imdbInfo?.Ratings?.Total 643 | ? `[center][img]https://i.imgur.com/sEpKj3O.png[/img][size=6]${imdbInfo.Ratings.Total}[/size][/center]\n` 644 | : '', 645 | Plot: imdbInfo?.Plot 646 | ? `[hr][/hr][indent][size=6][forumcolor][b]Plot[/b][/forumcolor][/size][/indent]\n\n${imdbInfo.Plot}` 647 | : '', 648 | Search: imdbInfo?.ID 649 | ? `[center][url=https://www.imdb.com/title/${imdbInfo.ID}][img width='46px']https://i.imgur.com/KO5Twbs.png[/img][/url]` 650 | : '[center][img width="46px"]https://i.imgur.com/KO5Twbs.png[/img][/url]', 651 | Details: movieInfo, 652 | Genres: imdbInfo?.Genres, 653 | TitleSimple: imdbInfo?.Title, 654 | }; 655 | } 656 | } 657 | 658 | /////////////////////////////////////////////////////////////////////////// 659 | // Main Generation // 660 | /////////////////////////////////////////////////////////////////////////// 661 | 662 | /** 663 | * Create's extra BBCode not related to the body message. 664 | * @param {string} mediainfo FULL mediainfo from Mediainfo Application 665 | * @param {string} title Title from the IMDB Scraper. 666 | * @param {array} genres Genres from the IMDB Scraper. 667 | * @returns {object} - Compiled BBCode 668 | */ 669 | const GenerateExtras = (mediainfo, title, genres) => { 670 | const mediaScraper = new Mediainfo(mediainfo); 671 | const media = mediaScraper.create(); 672 | let tags = genres ? genres : []; 673 | title = [ 674 | title, 675 | media.VideoResolution, 676 | media.BitDepth, 677 | media.VideoLibrary, 678 | ].join(' '); 679 | if (media.video?.includes('Dolby Vision')) { 680 | tags.push('Dolby Vision'); 681 | title += ' Dolby Vision'; 682 | } 683 | if (media.video?.includes('HDR10+ Profile')) { 684 | tags.push('hdr10plus'); 685 | title += ' HDR10Plus'; 686 | } else if (media.video?.includes('HDR10 Compatible')) { 687 | tags.push('hdr10'); 688 | title += ' HDR10'; 689 | } 690 | title += ` ${media.AudioCodec}`; 691 | if ( 692 | [ 693 | 129, 172, 173, 174, 175, 176, 178, 179, 180, 181, 183, 184, 202, 204, 694 | ].includes(parseInt(window.location.href.match(/\d+/, '')[0])) 695 | ) { 696 | title += ` ${media.Size}`; 697 | } 698 | return { 699 | title: title, 700 | tags: tags, 701 | mediainfo: `[hr][/hr][indent][size=6][forumcolor][b]Media Info[/b][/forumcolor][/size][/indent]\n[spoiler='Click here to view Media Info']\n${mediainfo}\n[/spoiler]\n`, 702 | }; 703 | }; 704 | 705 | /** 706 | * Send's generated data into DOM 707 | * @param {string} forumBBcode Body Message for the post. 708 | * @param {string[]} tags Tags to add to the post. 709 | * @param {string} title Full title for the post. 710 | * @param {boolean} titleBool Depict sending title data. 711 | * @returns {void} 712 | */ 713 | const PasteToForum = (forumBBcode, tags, title, titleBool) => { 714 | try { 715 | document.getElementsByName('message')[0].value = forumBBcode; 716 | } catch (err) { 717 | RemoveAllChildNodes( 718 | document.getElementsByClassName('fr-element fr-view')[0] 719 | ); 720 | let p = document.createElement('p'); 721 | p.innerText = forumBBcode; 722 | document.getElementsByClassName('fr-element fr-view')[0].appendChild(p); 723 | } finally { 724 | if (tags) { 725 | document.getElementsByName('tags')[0].value = tags.join(', '); 726 | for (let tag of tags) { 727 | TagsPush(tag); 728 | } 729 | } 730 | if (titleBool) { 731 | document.getElementsByClassName('js-titleInput')[0].value = title; 732 | } 733 | } 734 | }; 735 | 736 | const generateTemplate = async () => { 737 | const [imdbInput, downloadLinks, mediaInfo] = [ 738 | document.getElementById('searchID').value, 739 | document.getElementById('ddl').value, 740 | document.getElementById('mediaInfo').value, 741 | ]; 742 | if (!imdbInput || !downloadLinks || !mediaInfo) { 743 | let errors = ''; 744 | errors += !imdbInput ? "
  • You Didn't Enter an IMDB ID or Link!
  • " : ''; 745 | errors += !downloadLinks 746 | ? "
  • You Forgot Your Download Link! That's Pretty Important...!
  • " 747 | : ''; 748 | errors += !mediaInfo 749 | ? "
  • You Don't Have Any Mediainfo? It's Required!
  • " 750 | : ''; 751 | Popup(errors); 752 | return; 753 | } 754 | const bbcodeHandler = new BBCodeGenerator(); 755 | const downloadBBCode = bbcodeHandler.download(downloadLinks); 756 | const screenshotsBBCode = bbcodeHandler.screenshots( 757 | document.querySelector('#screensLinks').value 758 | ); 759 | const youtubeLink = document.getElementById('ytLink').value; 760 | const trailer = youtubeLink.match(/[a-z]/) 761 | ? `\n[hr][/hr][indent][size=6][forumcolor][b]Trailer[/b][/forumcolor][/size][/indent]\n ${youtubeLink}` 762 | : ''; 763 | const imdbInfo = await bbcodeHandler.imdb(imdbInput); 764 | const titleBool = !document.getElementsByClassName('js-titleInput')[0].value; 765 | const extras = GenerateExtras( 766 | mediaInfo, 767 | imdbInfo.TitleSimple, 768 | imdbInfo.Genres 769 | ); 770 | PasteToForum( 771 | `${imdbInfo.Poster}${imdbInfo.Title}${imdbInfo.Search} ${imdbInfo.Rating}${imdbInfo.TotalRatings}${imdbInfo.Plot}${trailer}${screenshotsBBCode}${imdbInfo.Details}${extras.mediainfo}${downloadBBCode}`, 772 | extras.tags, 773 | extras.title, 774 | titleBool 775 | ); 776 | }; 777 | 778 | /////////////////////////////////////////////////////////////////////////// 779 | // Main // 780 | /////////////////////////////////////////////////////////////////////////// 781 | 782 | /** 783 | * The main function being ran. 784 | * Pushes our HTML to the DOM. 785 | * Generates Event Listeners on our buttons. 786 | */ 787 | const main = () => { 788 | document.getElementsByTagName('dd')[0].innerHTML += htmlTemplate; 789 | document.querySelector('#hideTemplate').addEventListener( 790 | 'click', 791 | () => { 792 | HideTemplate(); 793 | }, 794 | false 795 | ); 796 | document.querySelector('#showTemplate').addEventListener( 797 | 'click', 798 | () => { 799 | ShowTemplate(); 800 | }, 801 | false 802 | ); 803 | document.querySelector('#generateTemplate').addEventListener( 804 | 'click', 805 | () => { 806 | generateTemplate(); 807 | }, 808 | false 809 | ); 810 | }; 811 | 812 | addStyle(` 813 | @media screen and (min-width: 300px) { 814 | /* Reactscore & Posts */ 815 | input[type='number'] { 816 | border-bottom: 2px solid teal; 817 | border-image: linear-gradient(to right, #11998e, #38ef7d); 818 | border-image-slice: 1; 819 | background: transparent; 820 | color: white; 821 | max-width: 35px; 822 | } 823 | #textareaDivider { 824 | margin-top: -11px; 825 | } 826 | /* Start Rounded sliders Checkboxes */ 827 | .switch { 828 | position: relative; 829 | display: inline-block; 830 | width: 42px; 831 | height: 17px; 832 | } 833 | .switch input { 834 | opacity: 0; 835 | width: 0; 836 | height: 0; 837 | } 838 | .slider { 839 | position: absolute; 840 | cursor: pointer; 841 | top: 0; 842 | left: 0; 843 | right: 0; 844 | bottom: 0; 845 | background-color: #ccc; 846 | -webkit-transition: 0.4s; 847 | transition: 0.4s; 848 | } 849 | .slider:before { 850 | position: absolute; 851 | content: ''; 852 | height: 13px; 853 | width: 13px; 854 | left: 2px; 855 | bottom: 2px; 856 | background-color: #42464d; 857 | -webkit-transition: 0.4s; 858 | transition: 0.4s; 859 | } 860 | input:checked + .slider { 861 | background-color: #4caf50; 862 | } 863 | input:focus + .slider { 864 | box-shadow: 0 0 1px #4caf50; 865 | } 866 | input:checked + .slider:before { 867 | -webkit-transform: translateX(26px); 868 | -ms-transform: translateX(26px); 869 | transform: translateX(26px); 870 | } 871 | .slider.round { 872 | border-radius: 34px; 873 | } 874 | .slider.round:before { 875 | border-radius: 50%; 876 | } 877 | } 878 | @media screen and (min-width: 768px) { 879 | /* Reactscore & Posts */ 880 | input[type='number'] { 881 | border-bottom: 2px solid teal; 882 | border-image: linear-gradient(to right, #11998e, #38ef7d); 883 | border-image-slice: 1; 884 | background: transparent; 885 | color: white; 886 | max-width: 35px; 887 | } 888 | #textareaDivider { 889 | margin-top: -11px; 890 | } 891 | .switch { 892 | position: relative; 893 | display: inline-block; 894 | width: 42px; 895 | height: 17px; 896 | } 897 | .switch input { 898 | opacity: 0; 899 | width: 0; 900 | height: 0; 901 | } 902 | .slider { 903 | position: absolute; 904 | cursor: pointer; 905 | top: 0; 906 | left: 0; 907 | right: 0; 908 | bottom: 0; 909 | background-color: #ccc; 910 | -webkit-transition: 0.4s; 911 | transition: 0.4s; 912 | } 913 | .slider:before { 914 | position: absolute; 915 | content: ''; 916 | height: 13px; 917 | width: 13px; 918 | left: 2px; 919 | bottom: 2px; 920 | background-color: #42464d; 921 | -webkit-transition: 0.4s; 922 | transition: 0.4s; 923 | } 924 | input:checked + .slider { 925 | background-color: #4caf50; 926 | } 927 | input:focus + .slider { 928 | box-shadow: 0 0 1px #4caf50; 929 | } 930 | input:checked + .slider:before { 931 | -webkit-transform: translateX(26px); 932 | -ms-transform: translateX(26px); 933 | transform: translateX(26px); 934 | } 935 | /* Rounded sliders */ 936 | .slider.round { 937 | border-radius: 34px; 938 | } 939 | .slider.round:before { 940 | border-radius: 50%; 941 | } 942 | }`); 943 | 944 | main(); 945 | --------------------------------------------------------------------------------