├── README.md
└── script.user.js
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Blackpearl OMDB Template Generator
3 | OMDB Thread Template Generator userscript
4 |
5 | 
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  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 | Show
24 |
48 | `;
49 |
50 | const omdbinput = `
51 |
52 | Show
53 |
54 |
55 |
56 |
Save Key
57 |
Clear
58 |
Hide
59 |
60 | `;
61 |
62 | var errPopup = `
63 |
64 |
65 | Oops! We ran into some problems.
66 |
`;
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 |
--------------------------------------------------------------------------------