(() => { /** * Plugin Name: improvedStorageFunctionality * Description: Улучшение функциональности файлового хранилища * Version: 1.2 * Author: Никита Трофимов * Author URL: https://t.me/NiktarioN * Author: Александр Серов * Author URL: https://t.me/sserov */ ////////////////////////////////////////////////////////////////////////////////////// // ПАНЕЛЬ УПРАВЛЕНИЯ. НАЧАЛО const SETTINGS = { /** * Поддерживаемые медиа форматы * type: 'image' - тип медиа(image/video/audio) * extensions: ['jpg'] - массив поддерживаемых расширений файлов * Если нужно добавить новый поддерживаемый формат, то пропишите его через запятую в одинарных кавычках и в нижнем регистре */ formats: [ { type: 'image', extensions: [ 'apng', 'avif', 'png', 'jpg', 'jpeg', 'jfif', 'pjpeg', 'pjp', 'heic', 'gif', 'svg', ], }, { type: 'video', extensions: ['mp4', 'mov', 'wmv', 'avi', 'avchd', 'mkv', 'webm'], }, { type: 'audio', extensions: ['mp3', 'ogg', 'wav', 'oga', 'aac'], }, ], /** * Как копировать ссылки * pathname - копируется только pathname часть урла, без hostname * full - копируется весь урл */ copyLinkMode: 'pathname', }; ////////////////////////////////////////////////////////////////////////////////////// // ПАНЕЛЬ УПРАВЛЕНИЯ. КОНЕЦ const getLink = (row, fileNameColumnNodeIndex) => { const tds = row.querySelectorAll('td'); const fileNameColumn = tds[fileNameColumnNodeIndex]; const link = fileNameColumn.querySelector('a').href; return link; }; const getLinkType = (link) => { const linkType = SETTINGS.formats.find(({ extensions }) => extensions.some((ext) => link.toLowerCase().endsWith(ext)) )?.type; return linkType; }; const getImagePreviewNode = (link) => { const img = document.createElement('img'); img.setAttribute('src', link); img.setAttribute('style', 'display: block; width: 200px'); return img; }; const getVideoPreviewNode = (link) => { const video = document.createElement('video'); video.setAttribute('controls', 'true'); video.setAttribute('src', link); video.setAttribute('style', 'display: block; width: 200px'); return video; }; const getAudioPreviewNode = (link) => { const audio = document.createElement('audio'); audio.setAttribute('controls', 'true'); audio.setAttribute('style', 'display: block; width: 300px'); const source = document.createElement('source'); source.setAttribute('src', link); source.setAttribute('type', 'audio/ogg'); source.setAttribute('type', 'audio/mpeg'); audio.appendChild(source); return audio; }; const improvedStorageFunctionality = () => { const getLinkPreviewNode = (link) => { const map = { image: getImagePreviewNode, video: getVideoPreviewNode, audio: getAudioPreviewNode, }; const linkType = getLinkType(link); if (!linkType) { return; } const previewNode = map[linkType](link); return previewNode; }; const improveTable = () => { if ( !/fileservice\/control\/account\/((video)|(deleted)|(storage))/.test( window.location.href ) ) { return; } const tableHead = document.querySelectorAll('#w5-container table tr')[0]; const headItems = tableHead.querySelectorAll('th'); const fileNameColumnNodeIndex = Array.from(headItems).findIndex( (item) => item.textContent === 'Имя файла' ); if (fileNameColumnNodeIndex === -1) { return; } const idColumnNodeIndex = Array.from(headItems).findIndex( (item) => item.textContent === 'ID' ); const relativePathColumnNodeIndex = Array.from(headItems).findIndex( (item) => item.textContent === 'Относительный путь' ); const addCopyLinkButton = (row) => { if ( relativePathColumnNodeIndex === -1 || fileNameColumnNodeIndex === -1 ) { return; } const tds = row.querySelectorAll('td'); const IDColumn = tds[idColumnNodeIndex]; const relativePathColumn = tds[relativePathColumnNodeIndex]; const linkUrl = new URL(IDColumn.querySelector('a').href); const iconButton = document.createElement('i'); iconButton.classList.add('fa', 'fa-clipboard'); iconButton.setAttribute('style', 'display: block; cursor: pointer;'); fetch(linkUrl) .then((data) => { return data.text(); }) .then((htmlString) => { const parser = new DOMParser(); const doc = parser.parseFromString(htmlString, 'text/html'); const linkToFile = doc.querySelector( 'input.form-control[type="text"]' ).value; iconButton.addEventListener('click', () => { const url = new URL(linkToFile); const copyText = SETTINGS.copyLinkMode === 'full' ? linkToFile : url.pathname; navigator.clipboard.writeText(copyText); iconButton.setAttribute( 'style', 'display: block; cursor: pointer; color: #28a745' ); }); relativePathColumn.appendChild(iconButton); }); }; const tableRows = document.querySelectorAll( '#w5-container table tbody tr' ); if ( tableRows.length === 1 && tableRows[0].textContent === 'Нет результатов' ) { return; } tableRows.forEach((row) => { const tds = row.querySelectorAll('td'); const fileNameColumn = tds[fileNameColumnNodeIndex]; const link = getLink(row, fileNameColumnNodeIndex); const previewNode = getLinkPreviewNode(link); if (previewNode) { fileNameColumn.appendChild(previewNode); } addCopyLinkButton(row); }); }; improveTable(); const improveUpload = () => { if ( !/fileservice\/control\/account\/storage/.test(window.location.href) ) { return; } $('.uploadify-container').data('uploadifive').settings.onUploadComplete = (e, res) => { const itemNode = e.queueItem[0]; const fileInfoNode = itemNode.querySelector('.fileinfo').parentNode; const linkNode = document.createElement('a'); const link = `/fileservice/control/account/file-by-hash?hash=${res}`; linkNode.setAttribute('href', link); linkNode.setAttribute('style', 'display: block'); linkNode.textContent = res; fileInfoNode.appendChild(linkNode); const iconButton = document.createElement('i'); iconButton.classList.add('fa', 'fa-clipboard'); iconButton.setAttribute('style', 'display: block; cursor: pointer;'); fetch(link) .then((data) => { return data.text(); }) .then((htmlString) => { const parser = new DOMParser(); const doc = parser.parseFromString(htmlString, 'text/html'); const linkToFile = doc.querySelector( 'input.form-control[type="text"]' ).value; iconButton.addEventListener('click', () => { const url = new URL(linkToFile); const copyText = SETTINGS.copyLinkMode === 'full' ? linkToFile : url.pathname; navigator.clipboard.writeText(copyText); iconButton.setAttribute( 'style', 'display: block; cursor: pointer; color: #28a745' ); }); fileInfoNode.appendChild(iconButton); }); }; }; improveUpload(); const improveVideoEdit = () => { let currentVideos = null; let clickedButton = null; const editButtons = document.querySelectorAll('.setting-edit-link'); const lessonSettingsButtons = document.querySelectorAll( '.dropdown-menu .btn-settings' ); const settingsButtons = document.querySelectorAll( '.btn.btn-default.btn-settings' ); const handleUpdateCurrentVideosAndClickedButton = (node, clicked) => () => { currentVideos = node.querySelectorAll('[data-file-id]'); clickedButton = clicked; }; lessonSettingsButtons.forEach((editButton) => { editButton.addEventListener( 'click', handleUpdateCurrentVideosAndClickedButton( editButton.parentNode?.parentNode?.parentNode?.parentNode ?.parentNode, 'settings' ) ); }); editButtons.forEach((editButton) => { editButton.addEventListener( 'click', handleUpdateCurrentVideosAndClickedButton( editButton.parentNode, 'edit' ) ); }); settingsButtons.forEach((settingsButton) => { settingsButton.addEventListener( 'click', handleUpdateCurrentVideosAndClickedButton( settingsButton?.parentNode?.parentNode?.parentNode, 'settings' ) ); }); const observer = new MutationObserver((mutationList) => { mutationList.forEach(() => { const targetNodes = Array.from( document.querySelectorAll('.wvc-root') ).filter((item) => clickedButton === 'edit' ? item.clientHeight > 0 : true ); if (!targetNodes.length) { return; } targetNodes.forEach((targetNode, index) => { const isOpenInFileManagerLinkExist = targetNode.querySelector( '#video-link-to-file-manager' ); if (isOpenInFileManagerLinkExist) { return; } if (!currentVideos?.length) { return; } const fileId = currentVideos[index].dataset.fileId; const linkToFileManager = `/fileservice/control/account/file?id=${fileId}`; const a = document.createElement('a'); a.textContent = 'Открыть в файловом хранилище'; a.href = linkToFileManager; a.setAttribute('target', '_blank'); a.setAttribute('id', 'video-link-to-file-manager'); targetNode.appendChild(a); }); }); }); const config = { attributes: true, childList: true, subtree: false }; observer.observe(document.body, config); }; improveVideoEdit(); }; window.addEventListener('DOMContentLoaded', improvedStorageFunctionality); })();