Greasy Fork is available in English.

Kinozal Magnetizer + TorrServer

Magnet link-icon maker for kinozal.(tv|me|guru) + "Add to TorrServer" button

// ==UserScript==
// @name          Kinozal Magnetizer + TorrServer
// @description   Magnet link-icon maker for kinozal.(tv|me|guru) + "Add to TorrServer" button
// @version       1.12
// @match         *://kinozal.tv/details.php*
// @match	      *://kinozal.me/details.php*
// @match	      *://kinozal.guru/details.php*
// @match         *://kinozal.tv/browse.php*
// @match	      *://kinozal.me/browse.php*
// @match	      *://kinozal.guru/browse.php*
// @run-at        document-end

// @grant         GM_getValue
// @grant         GM_setValue
// @grant         GM_addStyle

// @copyright     2024, MSerj
// @license       MIT
// @namespace     https://greasyfork.org/en/users/1321619-mserj
// @icon          data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUiIGhlaWdodD0iMjUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNTkgNTkiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxwYXRoIHN0eWxlPSJmaWxsOiM0MjRBNjA7IiBkPSJNNDYsNDEuNUgyNmMtNi42MjcsMC0xMi01LjM3My0xMi0xMnYwYzAtNi42MjcsNS4zNzMtMTIsMTItMTJoMjB2LTE0SDI2Yy0xNC4zNTksMC0yNiwxMS42NDEtMjYsMjYJdjBjMCwxNC4zNTksMTEuNjQxLDI2LDI2LDI2aDIwVjQxLjV6Ij48L3BhdGg+PGc+CTxwYXRoIHN0eWxlPSJmaWxsOiNDN0NBQzc7IiBkPSJNNTMsNy41aDFjMC41NTIsMCwxLTAuNDQ3LDEtMXMtMC40NDgtMS0xLTFoLTFjLTAuNTUyLDAtMSwwLjQ0Ny0xLDFTNTIuNDQ4LDcuNSw1Myw3LjV6Ij48L3BhdGg+CTxwYXRoIHN0eWxlPSJmaWxsOiNDN0NBQzc7IiBkPSJNNDksNy41aDFjMC41NTIsMCwxLTAuNDQ3LDEtMXMtMC40NDgtMS0xLTFoLTFjLTAuNTUyLDAtMSwwLjQ0Ny0xLDFTNDguNDQ4LDcuNSw0OSw3LjV6Ij48L3BhdGg+CTxwYXRoIHN0eWxlPSJmaWxsOiNDN0NBQzc7IiBkPSJNNTcsNy41aDFjMC41NTIsMCwxLTAuNDQ3LDEtMXMtMC40NDgtMS0xLTFoLTFjLTAuNTUyLDAtMSwwLjQ0Ny0xLDFTNTYuNDQ4LDcuNSw1Nyw3LjV6Ij48L3BhdGg+CTxwYXRoIHN0eWxlPSJmaWxsOiNDN0NBQzc7IiBkPSJNNTQsMTMuNWgtMWMtMC41NTIsMC0xLDAuNDQ3LTEsMXMwLjQ0OCwxLDEsMWgxYzAuNTUyLDAsMS0wLjQ0NywxLTFTNTQuNTUyLDEzLjUsNTQsMTMuNXoiPjwvcGF0aD4JPHBhdGggc3R5bGU9ImZpbGw6I0M3Q0FDNzsiIGQ9Ik00OSwxNS41aDFjMC41NTIsMCwxLTAuNDQ3LDEtMXMtMC40NDgtMS0xLTFoLTFjLTAuNTUyLDAtMSwwLjQ0Ny0xLDFTNDguNDQ4LDE1LjUsNDksMTUuNXoiPjwvcGF0aD4JPHBhdGggc3R5bGU9ImZpbGw6I0M3Q0FDNzsiIGQ9Ik01OCwxMy41aC0xYy0wLjU1MiwwLTEsMC40NDctMSwxczAuNDQ4LDEsMSwxaDFjMC41NTIsMCwxLTAuNDQ3LDEtMVM1OC41NTIsMTMuNSw1OCwxMy41eiI+PC9wYXRoPgk8cGF0aCBzdHlsZT0iZmlsbDojQzdDQUM3OyIgZD0iTTUwLDEwLjVjMCwwLjU1MywwLjQ0OCwxLDEsMWgxYzAuNTUyLDAsMS0wLjQ0NywxLTFzLTAuNDQ4LTEtMS0xaC0xQzUwLjQ0OCw5LjUsNTAsOS45NDcsNTAsMTAuNXoiPjwvcGF0aD4JPHBhdGggc3R5bGU9ImZpbGw6I0M3Q0FDNzsiIGQ9Ik01NCwxMC41YzAsMC41NTMsMC40NDgsMSwxLDFoMWMwLjU1MiwwLDEtMC40NDcsMS0xcy0wLjQ0OC0xLTEtMWgtMUM1NC40NDgsOS41LDU0LDkuOTQ3LDU0LDEwLjV6Ij48L3BhdGg+CTxwYXRoIHN0eWxlPSJmaWxsOiNDN0NBQzc7IiBkPSJNNTQsNDQuNWgtMWMtMC41NTIsMC0xLDAuNDQ3LTEsMXMwLjQ0OCwxLDEsMWgxYzAuNTUyLDAsMS0wLjQ0NywxLTFTNTQuNTUyLDQ0LjUsNTQsNDQuNXoiPjwvcGF0aD4JPHBhdGggc3R5bGU9ImZpbGw6I0M3Q0FDNzsiIGQ9Ik00OSw0Ni41aDFjMC41NTIsMCwxLTAuNDQ3LDEtMXMtMC40NDgtMS0xLTFoLTFjLTAuNTUyLDAtMSwwLjQ0Ny0xLDFTNDguNDQ4LDQ2LjUsNDksNDYuNXoiPjwvcGF0aD4JPHBhdGggc3R5bGU9ImZpbGw6I0M3Q0FDNzsiIGQ9Ik01OCw0NC41aC0xYy0wLjU1MiwwLTEsMC40NDctMSwxczAuNDQ4LDEsMSwxaDFjMC41NTIsMCwxLTAuNDQ3LDEtMVM1OC41NTIsNDQuNSw1OCw0NC41eiI+PC9wYXRoPgk8cGF0aCBzdHlsZT0iZmlsbDojQzdDQUM3OyIgZD0iTTU0LDUyLjVoLTFjLTAuNTUyLDAtMSwwLjQ0Ny0xLDFzMC40NDgsMSwxLDFoMWMwLjU1MiwwLDEtMC40NDcsMS0xUzU0LjU1Miw1Mi41LDU0LDUyLjV6Ij48L3BhdGg+CTxwYXRoIHN0eWxlPSJmaWxsOiNDN0NBQzc7IiBkPSJNNTAsNTIuNWgtMWMtMC41NTIsMC0xLDAuNDQ3LTEsMXMwLjQ0OCwxLDEsMWgxYzAuNTUyLDAsMS0wLjQ0NywxLTFTNTAuNTUyLDUyLjUsNTAsNTIuNXoiPjwvcGF0aD4JPHBhdGggc3R5bGU9ImZpbGw6I0M3Q0FDNzsiIGQ9Ik01OCw1Mi41aC0xYy0wLjU1MiwwLTEsMC40NDctMSwxczAuNDQ4LDEsMSwxaDFjMC41NTIsMCwxLTAuNDQ3LDEtMVM1OC41NTIsNTIuNSw1OCw1Mi41eiI+PC9wYXRoPgk8cGF0aCBzdHlsZT0iZmlsbDojQzdDQUM3OyIgZD0iTTUzLDQ5LjVjMC0wLjU1My0wLjQ0OC0xLTEtMWgtMWMtMC41NTIsMC0xLDAuNDQ3LTEsMXMwLjQ0OCwxLDEsMWgxQzUyLjU1Miw1MC41LDUzLDUwLjA1Myw1Myw0OS41CQl6Ij48L3BhdGg+CTxwYXRoIHN0eWxlPSJmaWxsOiNDN0NBQzc7IiBkPSJNNTcsNDkuNWMwLTAuNTUzLTAuNDQ4LTEtMS0xaC0xYy0wLjU1MiwwLTEsMC40NDctMSwxczAuNDQ4LDEsMSwxaDFDNTYuNTUyLDUwLjUsNTcsNTAuMDUzLDU3LDQ5LjUJCXoiPjwvcGF0aD48L2c+PHJlY3QgeD0iMzIiIHk9IjMuNSIgc3R5bGU9ImZpbGw6I0VCQkExNjsiIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCI+PC9yZWN0PjxyZWN0IHg9IjMyIiB5PSI0MS41IiBzdHlsZT0iZmlsbDojRUJCQTE2OyIgd2lkdGg9IjE0IiBoZWlnaHQ9IjE0Ij48L3JlY3Q+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+
// ==/UserScript==

// Styles for the download button
GM_addStyle(`.mserj-download-btn {
    display: inline-block;
    height: 32px;
    width: 32px;
    border: none;
    background-image: url(data:image/webp;base64,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);
    background-size: 32px 32px;
  }`)

// Styles for setting modal
GM_addStyle('#mserj_settings { width: 400px; min-height: 150px; position: fixed; left: 0; top: 0; background-color: #fff; border: 1px solid #a00; }')
GM_addStyle(`#mserj_settings .header {\tbackground: #f1d29c;\tpadding: 10px;\tfont-weight: bold; text-align: center; }`)
GM_addStyle('#mserj_settings .fields { padding: 5px; }')
GM_addStyle('#mserj_settings .fields .row { display: flex; margin-bottom: 10px; }')
GM_addStyle('#mserj_settings .fields .row .label { display: flex; align-items: center; }')
GM_addStyle('#mserj_settings .fields .row .label span { margin-right: 10px; }')
GM_addStyle('#mserj_settings .fields .row .label span:first-child { width: 100px; }')

// Magnet icon SVG data
const magnetIcon = `
  <svg width="25" height="25" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 59 59" xml:space="preserve">
    <path style="fill:#424A60;" d="M46,41.5H26c-6.627,0-12-5.373-12-12v0c0-6.627,5.373-12,12-12h20v-14H26c-14.359,0-26,11.641-26,26 v0c0,14.359,11.641,26,26,26h20V41.5z"/>
    <g>
      <path style="fill:#C7CAC7;" d="M53,7.5h1c0.552,0,1-0.447,1-1s-0.448-1-1-1h-1c-0.552,0-1,0.447-1,1S52.448,7.5,53,7.5z"/>
      <path style="fill:#C7CAC7;" d="M49,7.5h1c0.552,0,1-0.447,1-1s-0.448-1-1-1h-1c-0.552,0-1,0.447-1,1S48.448,7.5,49,7.5z"/>
      <path style="fill:#C7CAC7;" d="M57,7.5h1c0.552,0,1-0.447,1-1s-0.448-1-1-1h-1c-0.552,0-1,0.447-1,1S56.448,7.5,57,7.5z"/>
      <path style="fill:#C7CAC7;" d="M54,13.5h-1c-0.552,0-1,0.447-1,1s0.448,1,1,1h1c0.552,0,1-0.447,1-1S54.552,13.5,54,13.5z"/>
      <path style="fill:#C7CAC7;" d="M49,15.5h1c0.552,0,1-0.447,1-1s-0.448-1-1-1h-1c-0.552,0-1,0.447-1,1S48.448,15.5,49,15.5z"/>
      <path style="fill:#C7CAC7;" d="M58,13.5h-1c-0.552,0-1,0.447-1,1s0.448,1,1,1h1c0.552,0,1-0.447,1-1S58.552,13.5,58,13.5z"/>
      <path style="fill:#C7CAC7;" d="M50,10.5c0,0.553,0.448,1,1,1h1c0.552,0,1-0.447,1-1s-0.448-1-1-1h-1C50.448,9.5,50,9.947,50,10.5z"/>
      <path style="fill:#C7CAC7;" d="M54,10.5c0,0.553,0.448,1,1,1h1c0.552,0,1-0.447,1-1s-0.448-1-1-1h-1C54.448,9.5,54,9.947,54,10.5z"/>
      <path style="fill:#C7CAC7;" d="M54,44.5h-1c-0.552,0-1,0.447-1,1s0.448,1,1,1h1c0.552,0,1-0.447,1-1S54.552,44.5,54,44.5z"/>
      <path style="fill:#C7CAC7;" d="M49,46.5h1c0.552,0,1-0.447,1-1s-0.448-1-1-1h-1c-0.552,0-1,0.447-1,1S48.448,46.5,49,46.5z"/>
      <path style="fill:#C7CAC7;" d="M58,44.5h-1c-0.552,0-1,0.447-1,1s0.448,1,1,1h1c0.552,0,1-0.447,1-1S58.552,44.5,58,44.5z"/>
      <path style="fill:#C7CAC7;" d="M54,52.5h-1c-0.552,0-1,0.447-1,1s0.448,1,1,1h1c0.552,0,1-0.447,1-1S54.552,52.5,54,52.5z"/>
      <path style="fill:#C7CAC7;" d="M50,52.5h-1c-0.552,0-1,0.447-1,1s0.448,1,1,1h1c0.552,0,1-0.447,1-1S50.552,52.5,50,52.5z"/>
      <path style="fill:#C7CAC7;" d="M58,52.5h-1c-0.552,0-1,0.447-1,1s0.448,1,1,1h1c0.552,0,1-0.447,1-1S58.552,52.5,58,52.5z"/>
      <path style="fill:#C7CAC7;" d="M53,49.5c0-0.553-0.448-1-1-1h-1c-0.552,0-1,0.447-1,1s0.448,1,1,1h1C52.552,50.5,53,50.053,53,49.5z"/>
      <path style="fill:#C7CAC7;" d="M57,49.5c0-0.553-0.448-1-1-1h-1c-0.552,0-1,0.447-1,1s0.448,1,1,1h1C56.552,50.5,57,50.053,57,49.5z"/>
    </g>
    <rect x="32" y="3.5" style="fill:#EBBA16;" width="14" height="14"/>
    <rect x="32" y="41.5" style="fill:#EBBA16;" width="14" height="14"/>
  </svg>
`

// TorrServer icon
const torrServerIcon = `<img src="data:image/png;base64,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" width="25px" height="25px"  alt="TorrServer" />`

/**
 * Settings stuff
 */
let settings = {}
const loadSettings = () => {
	settings = {
		showMagnetButton: GM_getValue('showMagnetButton', true),
		showDownloadButton: GM_getValue('showDownloadButton', false),
		showAddToTorrServerButton: GM_getValue('showAddToTorrServerButton', false),
		torrServerIp: GM_getValue('torrServerIp', 'localhost'),
		torrServerPort: GM_getValue('torrServerPort', 8090),
		torrServerLogin: GM_getValue('torrServerLogin', ''),
		torrServerPassword: GM_getValue('torrServerPassword', '')
	}
}

// modal to configure settings
const toggleSettings = () => {
	const $sett_wnd = $('#mserj_settings'),
		x = parseInt(($(window).width() - $sett_wnd.width()) / 2),
		y = parseInt(($(window).height() - $sett_wnd.height()) / 2)

	$('#mserj_showMagnetButton').attr('checked', !!settings.showMagnetButton)
	$('#mserj_showDownloadButton').attr('checked', !!settings.showDownloadButton)

	$('#mserj_showAddToTorrServerButton').attr('checked', !!settings.showAddToTorrServerButton)
	$('#mserj_torrServerIp').val(settings.torrServerIp)
	$('#mserj_torrServerPort').val(settings.torrServerPort)
	$('#mserj_torrServerLogin').val(settings.torrServerLogin)
	$('#mserj_torrServerPassword').val(settings.torrServerPassword)

	$('#mserj_settings').css({ left: x, top: y }).toggle('fast')
}

const attachSettingsModal = () => {
	const $tab = $('<li><a href="javascript:;" title="Настройки скрипта Kinozal Magnetizer"><div>Настройки</div></a></li>')

	$tab.click(toggleSettings)
	$('.menu > ul').append($tab)

	const modal = $(`
	  <div id="mserj_settings" style="display: none">
	    <div class="header">Настройка скрипта</div>
	    <div class="fields">
	      <div class="row">
	        <label class="label">
	          <input type="checkbox" id="mserj_showMagnetButton">
	          <span>Показывать кнопку "magnet"</span>
	          ${magnetIcon}
	        </label>
	      </div>
	      <div class="row">
	        <label class="label">
	          <input type="checkbox" id="mserj_showDownloadButton">
	          <span>Показывать кнопку "скачать"</span>
	          <button class="mserj-download-btn"></button>
	        </label>
	      </div>
	      <div class="row">
	        <label class="label">
	          <input type="checkbox" id="mserj_showAddToTorrServerButton">
	          <span>Показывать кнопку "TorrServer"</span>
	          ${torrServerIcon}
	        </label>
	      </div>
	      <div class="row">
	        <label class="label">
	          <span>TorrServer IP</span>
	          <input type="text" id="mserj_torrServerIp">
	        </label>
	      </div>
	      <div class="row">
	        <label class="label">
	          <span>TorrServer Port</span>
	          <input type="text" id="mserj_torrServerPort">
	        </label>
	      </div>
	      <div class="row">
	        <label class="label">
	          <span>TorrServer Login</span>
	          <input type="text" id="mserj_torrServerLogin">
	        </label>
	      </div>
	      <div class="row">
	        <label class="label">
	          <span>TorrServer Password</span>
	          <input type="password" id="mserj_torrServerPassword">
	        </label>
	      </div>
	      <div class="row" style="justify-content: center">
	        <input type="button" value="Сохранить настройки" id="mserj_save_settings" />
	      </div>
	    </div>
	  </div>
	`)
	$('body').append(modal)

	$('#mserj_save_settings').on('click', () => {
		GM_setValue('showMagnetButton', $('#mserj_showMagnetButton').is(':checked'))
		GM_setValue('showDownloadButton', $('#mserj_showDownloadButton').is(':checked'))

		GM_setValue('showAddToTorrServerButton', $('#mserj_showAddToTorrServerButton').is(':checked'))
		GM_setValue('torrServerIp', $('#mserj_torrServerIp').val())
		GM_setValue('torrServerPort', $('#mserj_torrServerPort').val())
		GM_setValue('torrServerLogin', $('#mserj_torrServerLogin').val())
		GM_setValue('torrServerPassword', $('#mserj_torrServerPassword').val())

		loadSettings()
		$('#mserj_settings').toggle('fast')
		location.reload()
	})
}

/**
 * TorrServer stuff
 */
function addToTorrServer(data) {
	$.ajax({
		method: 'POST',
		url: `${settings.torrServerIp}:${settings.torrServerPort}/torrents`,
		dataType: 'json',
		data: JSON.stringify({ action: 'add', save_to_db: true, ...data }),
		headers: {
			'Content-Type': 'application/json',
			...(settings.torrServerLogin &&
				settings.torrServerPassword && { Authorization: 'Basic ' + btoa(settings.torrServerLogin + ':' + settings.torrServerPassword) })
		},
		success: () => {
			alert('Успешно добавлено в TorrServer')
		},
		error: response => {
			if (response.status === 401) {
				alert('Авторизация не удалась! Проверьте ( соединение / логин / пароль )')
			} else {
				alert('Не удалось отправить запрос на TorrServer')
			}
		}
	})
}

// Fetch torrent poster
async function fetchTorrentPoster(url) {
	try {
		const response = await fetch(url)
		if (!response.ok) {
			throw new Error(`HTTP error! status: ${response.status}`)
		}
		const htmlString = await response.text()
		const parser = new DOMParser()
		const doc = parser.parseFromString(htmlString, 'text/html')

		const poster = doc.querySelector('img.p200')
		if (poster) {
			return poster.src
		} else {
			return null
		}
	} catch (error) {
		console.error('Error fetching or parsing HTML:', error)
		return null
	}
}

/**
 * handle search page case
 */
const processSearchPage = () => {
	// Function to fetch torrent hash and add download/magnet links
	async function processTorrentRow(row) {
		const torrentUrl = $(row).find('.nam a').attr('href')
		const uArgs = torrentUrl.split('?')[1].split('&')

		// Find torrent id
		let id = uArgs.find(el => el.startsWith('id='))?.split('=')[1]

		if (id) {
			if (settings.showDownloadButton) {
				// Create download button
				const downloadCell = document.createElement('td')
				const link = document.createElement('a')
				link.className = 'mserj-download-btn'
				link.href = `${location.origin}/download.php?id=${id}`
				downloadCell.appendChild(link)
				row.insertBefore(downloadCell, row.firstChild)
			}

			if (settings.showMagnetButton || settings.showAddToTorrServerButton) {
				// Fetch torrent hash
				const response = await fetch(`/get_srv_details.php?id=${id}&action=2`)
				const html = await response.text()
				const dom = new DOMParser().parseFromString(html, 'text/html')
				const torrentHash = dom.querySelector('ul > li:first-child')?.innerText.substr(10)

				if (settings.showMagnetButton && torrentHash) {
					// Create magnet link
					const magnetCell = document.createElement('td')
					const magnetLink = document.createElement('a')
					magnetLink.title = 'Magnet-ссылка' // Assuming 'ссылка' means 'link'
					magnetLink.href = `magnet:?xt=urn:btih:${torrentHash}`
					magnetLink.style.display = 'block'
					magnetLink.style.fontSize = '0px'
					magnetLink.innerHTML = magnetIcon

					magnetCell.appendChild(magnetLink)
					row.insertBefore(magnetCell, row.firstChild)
				}

				// Adding "add to torrServer" button to the page.
				if (settings.showAddToTorrServerButton && torrentHash) {
					// Create torrServer button
					const torrServerCell = document.createElement('td')
					const torrServerButton = document.createElement('button')
					torrServerButton.id = `add_to_torrserver-${id}`
					torrServerButton.title = 'Добавить в TorrServer'
					torrServerButton.style.display = 'block'
					torrServerButton.style.fontSize = '0px'
					torrServerButton.style.border = 'none'
					torrServerButton.style.padding = '0px'
					torrServerButton.style.cursor = 'pointer'
					torrServerButton.innerHTML = torrServerIcon

					torrServerCell.appendChild(torrServerButton)
					if (settings.showMagnetButton) {
						row.firstChild.parentNode.insertBefore(torrServerCell, row.firstChild.nextSibling) // something like row.insertAfter(torrServerCell, row.firstChild)
					} else {
						row.insertBefore(torrServerCell, row.firstChild)
					}

					$(`#add_to_torrserver-${id}`).on('click', () => {
						;(async () => {
							const poster = await fetchTorrentPoster(torrentUrl)
							addToTorrServer({
								link: `magnet:?xt=urn:btih:${torrentHash}`,
								poster
							})
						})()
					})
				}
			}
		}
	}

	const table = $('.t_peer')
	const tableHeader = table.find('.mn')

	// Add empty cells for download and magnet links in the table header
	settings.showDownloadButton && tableHeader.prepend('<td class="z"></td>')
	settings.showMagnetButton && tableHeader.prepend('<td class="z"></td>')
	settings.showAddToTorrServerButton && tableHeader.prepend('<td class="z"></td>')

	// Process each row in the table (excluding the header row)
	table
		.find('tr')
		.not(tableHeader)
		.each((i, row) => {
			processTorrentRow(row)
		})
}

/**
 * handle details page case
 */
const processDetailsPage = async () => {
	// Finding download button cell.
	const downloadCell = document.querySelector('.w100p td:first-of-type')

	// Fetching torrent hash string.
	const response = await (await fetch(`/get_srv_details.php?id=${new URL(location.href).searchParams.get('id')}&action=2`)).text()

	// Converting response text to dom element, so we can easily traverse and extract torrent hash with querySelector.
	const dom = new DOMParser().parseFromString(response, 'text/html')
	const torrentHash = dom.documentElement.querySelector('ul > li:first-child').innerText.substr(10)

	// Adding magnet link to the page.
	if (settings.showMagnetButton) {
		downloadCell.insertAdjacentHTML(
			'beforebegin',
			`<td style="width: 30px;"><a title="Magnet-ссылка" href="magnet:?xt=urn:btih:${torrentHash}" style="display: block; font-size: 0;">${magnetIcon}</a></td>`
		)
	}

	// Adding "add to torrServer" button to the page.
	if (settings.showAddToTorrServerButton) {
		downloadCell.insertAdjacentHTML(
			'beforebegin',
			`<td style="width: 30px;"><button class="add_to_torrserver" title="Добавить в TorrServer" style="display: block; font-size: 0; border: none; padding: 0; cursor: pointer;">${torrServerIcon}</button></td>`
		)
		const poster = $('.p200').attr('src')
		$('.add_to_torrserver').on('click', e => {
			addToTorrServer({
				link: `magnet:?xt=urn:btih:${torrentHash}`,
				poster: poster.startsWith('http') ? poster : `${location.origin}/${poster}`
			})
		})
	}
}

/**
 * Main script starts here after page is ready
 */
$(document).ready(function () {
	loadSettings()
	attachSettingsModal()
	switch (location.pathname) {
		case '/details.php':
			processDetailsPage()
			break
		case '/browse.php':
			processSearchPage()
			break
	}
})