peertube-plugin-transposer-connector
Version:
Transposer connector is a PeerTube language tool plugin to transcribe and translate with Whisper
2 lines (1 loc) • 33.1 kB
JavaScript
var it=Object.defineProperty;var G=Object.getOwnPropertySymbols;var at=Object.prototype.hasOwnProperty,rt=Object.prototype.propertyIsEnumerable;var j=(m,l,g)=>l in m?it(m,l,{enumerable:!0,configurable:!0,writable:!0,value:g}):m[l]=g,I=(m,l)=>{for(var g in l||(l={}))at.call(l,g)&&j(m,g,l[g]);if(G)for(var g of G(l))rt.call(l,g)&&j(m,g,l[g]);return m};async function mt({registerClientRoute:m,peertubeHelpers:l}){let{notifier:g}=l;function w(){return window.location.origin}m({route:"/transposer",onMount:({rootEl:p})=>{window.currentPage=1,window.videosPerPage=10;let lt='<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --><svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none"><path stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5h10M11 9h5"/><rect width="4" height="4" x="3" y="5" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" rx="1"/><path stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 15h10m-10 4h5"/><rect width="4" height="4" x="3" y="15" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" rx="1"/></svg>',dt='<?xml version="1.0" encoding="utf-8"?>\n <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->\n <svg fill="#000000" width="24" height="24" viewBox="-7 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg">\n <title>loading</title>\n <path d="M2.080 14.040l4-1.040c0.44-0.12 0.72-0.56 0.6-1.040-0.12-0.44-0.56-0.72-1.040-0.6l-2.080 0.56c0.68-0.88 1.56-1.6 2.64-2.080 1.64-0.72 3.44-0.76 5.12-0.12 1.64 0.64 2.96 1.92 3.68 3.52 0.2 0.44 0.68 0.6 1.12 0.44 0.44-0.2 0.6-0.68 0.44-1.12-0.88-2.040-2.52-3.6-4.6-4.44-2.080-0.8-4.36-0.76-6.4 0.12-1.36 0.6-2.48 1.52-3.36 2.68l-0.52-1.96c-0.12-0.44-0.56-0.72-1.040-0.6-0.44 0.12-0.72 0.56-0.6 1.040l1.040 4c0.12 0.56 0.4 0.8 1 0.64zM17.72 22.52l-1.040-3.96c0 0-0.16-0.8-0.96-0.6v0l-4 1.040c-0.44 0.12-0.72 0.56-0.6 1.040 0.12 0.44 0.56 0.72 1.040 0.6l2.080-0.56c-1.76 2.32-4.88 3.28-7.72 2.16-1.64-0.64-2.96-1.92-3.68-3.52-0.2-0.44-0.68-0.6-1.12-0.44-0.44 0.2-0.6 0.68-0.44 1.12 0.88 2.040 2.52 3.6 4.6 4.44 1 0.4 2 0.56 3.040 0.56 2.64 0 5.12-1.24 6.72-3.4l0.52 1.96c0.080 0.36 0.44 0.64 0.8 0.64 0.080 0 0.16 0 0.2-0.040 0.4-0.16 0.68-0.6 0.56-1.040z"></path>\n </svg>',y='<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M5.02502 12.0002C5.02526 8.66068 7.32548 5.78639 10.519 5.1351C13.7125 4.48382 16.9098 6.23693 18.1557 9.32231C19.4015 12.4077 18.3489 15.966 15.6415 17.8212C12.9341 19.6764 9.32601 19.3117 7.02377 16.9502C5.74387 15.6373 5.02489 13.8568 5.02502 12.0002Z" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M13.1819 5.1352C10.2334 4.53373 7.24846 5.98176 5.83137 8.70099C4.41427 11.4202 4.89879 14.7702 7.0245 16.9505C9.15022 19.1307 12.4165 19.6276 15.0677 18.1742C17.719 16.7208 19.1308 13.6593 18.5444 10.6352" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>',z='<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->\n <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M12 2.99988V5.99988M12 20.9999V17.9999M4.20577 16.4999L6.80385 14.9999M21 11.9999H18M16.5 19.7941L15 17.196M3 11.9999H6M7.5 4.20565L9 6.80373M7.5 19.7941L9 17.196M19.7942 16.4999L17.1962 14.9999M4.20577 7.49988L6.80385 8.99988" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>',b='<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM16.0303 8.96967C16.3232 9.26256 16.3232 9.73744 16.0303 10.0303L11.0303 15.0303C10.7374 15.3232 10.2626 15.3232 9.96967 15.0303L7.96967 13.0303C7.67678 12.7374 7.67678 12.2626 7.96967 11.9697C8.26256 11.6768 8.73744 11.6768 9.03033 11.9697L10.5 13.4393L12.7348 11.2045L14.9697 8.96967C15.2626 8.67678 15.7374 8.67678 16.0303 8.96967Z" fill="#1C274C"/></svg>',ct='<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 16H12.01M12 8V12M12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21Z" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>',st='<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-edit" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="#4CBDC9" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1" /><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z" /><path d="M16 5l3 3" /></svg>',gt='<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-trash" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="#4CBDC9" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M4 7l16 0" /><path d="M10 11l0 6" /><path d="M14 11l0 6" /><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12" /><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3" /></svg>';p.innerHTML=F();let B=document.createElement("style");B.innerHTML=O(),p.appendChild(B);let P=p.querySelector("#loadingIndicator");P&&(P.style.display="flex"),_();function F(){return'\n <div id="plugincontainer">\n <h1>Transposer</h1>\n <div id="loadingIndicator" class="loading-circle">\n <div class="spinner"></div>\n </div>\n <table id="myTable">\n \n </table>\n <div id="pageButtonsContainer">\n </div>\n <div id="messageContainer">\n </div>\n <!-- Add custom modal dialog -->\n <div id="confirmationModal" class="modal" style="display:none;">\n <div class="modal-content">\n <h3>Confirm Action</h3>\n <p id="confirmationMessage">There is already a transcription. Do you want to overwrite it?</p>\n <div class="modal-buttons">\n <button id="confirmButton">Yes, Overwrite</button>\n <button id="cancelButton">No, Cancel</button>\n </div>\n </div>\n </div>\n </div>\n '}async function v(e=0,n=window.videosPerPage){let i=p.querySelector("#loadingIndicator");i.style.display="flex";let a=p.querySelector("#myTable");a.innerHTML="",a.classList.add("loading");var d=w();console.log(e),console.log(n);let t="".concat(d,"/api/v1/users/me/videos/?start=").concat(e,"&count=").concat(n);console.log(t);try{await fetch(t,{method:"GET",headers:l.getAuthHeader()}).then(o=>(console.log("api:",t),console.log("result:",o),o.json())).then(async o=>{let r=p.querySelector("#messageContainer");if(o.total==0){r.textContent="No Videos yet",i.style.display="none",a.classList.remove("loading");return}o.total>0&&(r.textContent=""),window.totalVideos=o.total;let c=document.createElement("tbody"),k=document.createElement("tr");k.innerHTML='\n <th>Published At</th>\n <th>Link</th>\n <th>Title</th>\n <th>Description</th>\n <th>Default Language</th>\n <th colspan="4" class="action-column-header">\n <div class="action-headers-container">\n <span class="action-header">Transcribe</span>\n <span class="action-header">Translate</span>\n <span class="action-header">Metadata</span>\n <span class="action-header">Edit</span>\n </div>\n </th>\n ',c.appendChild(k);for(let u of o.data){let h=u.id,Y=await fetch("".concat(w(),"/api/v1/videos/").concat(h,"/captions"),{method:"GET",headers:l.getAuthHeader()}).then(s=>s.ok?s.json():(console.error("Failed to fetch captions: ".concat(s.status)),{total:0,data:[]})).catch(s=>(console.error("Error fetching captions: ".concat(s)),{total:0,data:[]})),x=await fetch("".concat(l.getBaseRouterRoute(),"/language/metadata/video/").concat(h),{headers:l.getAuthHeader()}).then(s=>s.ok?s.json():(console.error("Failed to fetch metadata: ".concat(s.status)),{})).catch(s=>(console.error("Error fetching metadata: ".concat(s)),{})),J=Object.keys(x),$=new Set;J.forEach(s=>{x[s]&&Object.keys(x[s]).forEach(T=>{x[s][T]&&x[s][T].trim()!==""&&$.add(T)})});let L=$.size;var C=Y.total;let M=C>0,K=u.uuid,Q=u.shortUUID,pt=u.state.label,W=u.language.label,X=u.name,tt=u.description,S=new Date(u.publishedAt),nt="".concat(S.toLocaleDateString()," ").concat(S.toLocaleTimeString()),et=u.thumbnailPath,ot=u.url,V=document.createElement("tr");c.appendChild(V),V.innerHTML='\n <div id="videoId" hidden>'.concat(h,'</div>\n <div id="videoUuid" hidden>').concat(K,'</div>\n <div id="videoShortUuid" hidden>').concat(Q,'</div>\n <div id="alreadyTranscripted-').concat(h,'" hidden>').concat(M,'</div>\n <td id="formattedPublishedAtCell">').concat(nt,'</td>\n <td id="thumbnailCell"><img src="').concat(et,'" alt="Thumbnail" width="100" onclick="(function() {\n const videoUrl = \'').concat(ot,"';\n if (videoUrl) {\n window.open(videoUrl, '_blank');\n }\n })();\"></td>\n <td id=\"titleCell\">").concat(X,'</td>\n <td id="descriptionCell">').concat(tt,'</td>\n <td id="languageCell">').concat(W,'</td>\n <td id="actionCell" colspan="4">\n <div class="action-buttons-row">\n <div class="action-cell">\n <button id="triggerTranscription" data-id="').concat(h,'" class="action-button ').concat(M?"success":"not-triggered",'">\n ').concat(M?b:y,'\n <span class="counter-label">').concat(M?"1/1":"0/1",'</span>\n </button>\n </div>\n <div class="action-cell">\n <button id="triggerTranslation" data-id="').concat(h,'" class="action-button ').concat(C>0?"success":"not-triggered",'">\n ').concat(C>0?b:y,'\n <span class="counter-label">').concat(C,'/26</span>\n </button>\n </div>\n <div class="action-cell">\n <button id="triggerMetadataTranslation" data-id="').concat(h,'" class="action-button ').concat(L>0?"success":"not-triggered",'">\n ').concat(L>0?b:y,'\n <span class="counter-label">').concat(L,'/26</span>\n </button>\n </div>\n <div class="action-cell">\n <button id="triggerDetail" data-id="').concat(h,'" class="action-button edit">\n ').concat(Z(),"\n </button>\n </div>\n </div>\n</td>\n ")}a.appendChild(c),i.style.display="none",a.classList.remove("loading"),q(),N()}).catch(o=>{console.log("Error:",o),i.style.display="none",a.classList.remove("loading")})}catch(o){console.error("Error:",o),i.style.display="none",a.classList.remove("loading")}}let f=null;async function R(e){console.log("Checking transcription for video ID:",e);var n=!1,i=document.querySelector("#alreadyTranscripted-".concat(e));if(i&&(n=i.innerHTML==="true"),!e||isNaN(e)){console.error("Invalid videoId provided"),g.error("Invalid video ID");return}if(n){console.log("Video already has transcription, showing confirmation dialog"),f=e;let a=document.getElementById("confirmationModal"),d=document.getElementById("confirmationMessage");d.textContent="There is already a transcription for this video. Do you want to overwrite it?";let t=document.getElementById("confirmButton");t.textContent="Yes, Overwrite";let o=document.getElementById("cancelButton");o.textContent="No, Cancel",a.style.display="flex",document.getElementById("cancelButton").focus();return}E(e)}async function E(e){let n=document.querySelector('#triggerTranscription[data-id="'.concat(e,'"]'));if(n){let i=document.getElementById("confirmationModal"),a=document.getElementById("confirmationMessage");a.textContent="Transcription process may take up to 30 minutes. If it doesn't complete within this time, please contact support at support@displayeurope.eu.";let d=document.getElementById("confirmButton");d.textContent="OK",i.style.display="flex";let t=()=>{i.style.display="none",D(e,n),d.removeEventListener("click",t),c.removeEventListener("click",o),i.removeEventListener("click",r)},o=()=>{i.style.display="none",d.removeEventListener("click",t),c.removeEventListener("click",o),i.removeEventListener("click",r)},r=k=>{k.target===i&&(i.style.display="none",d.removeEventListener("click",t),c.removeEventListener("click",o),i.removeEventListener("click",r))};d.addEventListener("click",t);let c=document.getElementById("cancelButton");c.addEventListener("click",o),i.addEventListener("click",r)}}async function D(e,n){if(n){let i=n.innerHTML;n.innerHTML="".concat(z,'<span class="counter-label">Loading...</span>'),n.disabled=!0}try{let i=l.getAuthHeader(),a=await fetch("".concat(l.getBaseRouterRoute(),"/transposer/translate/").concat(e),{method:"POST",headers:I({"Content-Type":"application/json"},i),body:JSON.stringify({})});if(!a.ok){let t=await a.text();throw new Error("Translation request failed: ".concat(a.status," ").concat(t))}let d=await a.json();console.log("Translation result:",d),g.success("Translation sent successfully - now wait until completed"),n&&(n.innerHTML="".concat(b,'<span class="counter-label">1/1</span>'),n.classList.remove("not-triggered"),n.classList.add("success"),n.disabled=!1)}catch(i){g.error("Error transcribing video: ".concat(i)),console.error("Error transcribing video:",i),n&&(n.innerHTML="".concat(y,'<span class="counter-label">0/1</span>'),n.disabled=!1)}}function A(e){console.log("start translate all languages for Video",e),window.open("".concat(w(),"/p/transposer/translate?videoId=").concat(e),"_self")}function H(e){console.log("start translate Metadata",e),window.open("".concat(w(),"/p/transposer/translate/metadata?videoId=").concat(e),"_self")}function U(e){console.log("redirecting to video update page",e),window.open("".concat(w(),"/videos/update/").concat(e),"_self")}function q(){p.querySelectorAll("#triggerTranscription").forEach(r=>{var c=r.dataset.id;r.addEventListener("click",()=>{R(c)})});let n=p.querySelectorAll("#triggerTranslation");console.log(n),n.forEach(r=>{console.log(r),r.addEventListener("click",()=>{let c=r.dataset.id;A(c)})}),p.querySelectorAll("#triggerMetadataTranslation").forEach(r=>{r.addEventListener("click",()=>{let c=r.dataset.id;H(c)})}),p.querySelectorAll("#triggerDetail").forEach(r=>{r.addEventListener("click",()=>{let c=r.dataset.id;U(c)})});let d=document.getElementById("confirmButton"),t=document.getElementById("cancelButton"),o=document.getElementById("confirmationModal");d.addEventListener("click",()=>{f&&(E(f),f=null),o.style.display="none"}),t.addEventListener("click",()=>{console.log("Transcription cancelled by user"),f=null,o.style.display="none"}),o.addEventListener("click",r=>{r.target===o&&(f=null,o.style.display="none")})}function N(){let e=document.getElementById("pageButtonsContainer");e.innerHTML="";let n=window.currentPage;window.totalPages=Math.ceil(window.totalVideos/window.videosPerPage);let i=Math.max(1,n-2),a=Math.min(window.totalPages,i+4);if(a===window.totalPages&&(i=Math.max(1,a-4)),i>1){let t=document.createElement("button");t.textContent="\xAB",t.classList.add("page-button"),t.title="First page",t.addEventListener("click",async()=>{window.currentPage=1,await v(0,window.videosPerPage)}),e.appendChild(t)}if(n>1){let t=document.createElement("button");t.textContent="\u2039",t.classList.add("page-button"),t.title="Previous page",t.addEventListener("click",async()=>{window.currentPage=n-1,await v((window.currentPage-1)*window.videosPerPage,window.videosPerPage)}),e.appendChild(t)}for(let t=i;t<=a;t++){let o=document.createElement("button");o.textContent=t,o.classList.add("page-button"),o.disabled=t===n,t===n&&o.classList.add("current-page-button"),o.addEventListener("click",async()=>{t!==n&&(window.currentPage=t,await v((t-1)*window.videosPerPage,window.videosPerPage))}),e.appendChild(o)}if(n<window.totalPages){let t=document.createElement("button");t.textContent="\u203A",t.classList.add("page-button"),t.title="Next page",t.addEventListener("click",async()=>{window.currentPage=n+1,await v((window.currentPage-1)*window.videosPerPage,window.videosPerPage)}),e.appendChild(t)}if(a<window.totalPages){let t=document.createElement("button");t.textContent="\xBB",t.classList.add("page-button"),t.title="Last page",t.addEventListener("click",async()=>{window.currentPage=window.totalPages,await v((window.totalPages-1)*window.videosPerPage,window.videosPerPage)}),e.appendChild(t)}let d=document.createElement("span");d.classList.add("page-info"),d.textContent=" Page ".concat(n," of ").concat(window.totalPages," (").concat(window.totalVideos," videos) "),e.appendChild(d)}function O(){return'\n #plugincontainer {\n max-width: 100%;\n padding: 20px;\n position: relative;\n } \n \n #plugincontainer h1 {\n color: var(--mainColor);\n }\n \n #plugincontainer #formcontainer {\n display: flex;\n flex-wrap: wrap;\n }\n \n #plugincontainer .modifyButton,\n #plugincontainer .saveButton, \n #plugincontainer .cancelButton, \n #plugincontainer .deleteButton {\n cursor: pointer;\n padding: 20px;\n }\n \n #plugincontainer input, \n #plugincontainer textarea,\n #plugincontainer select {\n display: block;\n font-size: 16px;\n padding: var(--input-y-padding, 8px) var(--input-x-padding, 12px);\n width: 100%;\n max-width: 100%;\n color: var(--input-fg, #000);\n background-color: var(--input-bg, #fff);\n border: 1px solid var(--input-border-color, #ccc);\n border-radius: var(--input-border-radius, 4px);\n line-height: 24px;\n transition: background-color 0.3s ease;\n }\n \n #plugincontainer p {\n font-size: 18px;\n }\n \n #plugincontainer table {\n width: 100%;\n border-collapse: collapse;\n margin: 25px 0;\n font-size: 0.9em;\n min-width: 130px;\n min-height: 130px;\n }\n \n #plugincontainer table tr {\n text-align: left;\n }\n \n #plugincontainer table th,\n #plugincontainer table td {\n padding: 12px 15px;\n border-bottom: 1px solid var(--inputPlaceholderColor, #ccc);\n }\n \n #plugincontainer table th {\n background-color: var(--greyBackgroundColor, #f8f9fa);\n color: var(--mainForegroundColor);\n }\n \n /* General button styling */\n #plugincontainer button {\n color: var(--on-primary, var(--mainForegroundColor));\n background-color: var(--primary, var(--mainColor));\n border: 1px solid var(--primary, var(--mainColor));\n padding: var(--input-y-padding, 8px) var(--input-x-padding, 12px);\n border-radius: 4px;\n cursor: pointer;\n transition: background-color 0.3s;\n vertical-align: top;\n }\n \n /* Top-level action buttons */\n #plugincontainer > button {\n width: auto;\n min-width: 100px;\n margin-right: 10px;\n }\n \n /* Table buttons */\n #plugincontainer td button {\n width: auto;\n min-width: 80px;\n margin: 0 5px;\n }\n \n #plugincontainer button:hover {\n background-color: var(--secondaryColor);\n }\n \n #plugincontainer button:disabled {\n background-color: var(--greyBackgroundColor, #cccccc);\n color: var(--greyForegroundColor, #666666);\n cursor: not-allowed;\n }\n \n /* Action buttons like in the video list */\n #plugincontainer .action-button {\n position: relative;\n width: 56px;\n height: 56px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-width: unset;\n padding: 8px;\n }\n \n #plugincontainer .action-button.success {\n background-color: var(--primary, var(--mainColor));\n border-color: var(--primary, var(--mainColor));\n }\n \n #plugincontainer .action-button.not-triggered {\n background-color: var(--greyBackgroundColor, #f8f9fa);\n border-color: var(--greyForegroundColor, #ccc);\n color: var(--greyForegroundColor, #666);\n }\n \n #plugincontainer .action-button svg {\n width: 24px;\n height: 24px;\n margin-bottom: 6px;\n fill: var(--on-primary, var(--mainForegroundColor));\n stroke: var(--on-primary, var(--mainForegroundColor));\n }\n \n #plugincontainer .action-button.not-triggered svg {\n fill: var(--greyForegroundColor, #666);\n stroke: var(--greyForegroundColor, #666);\n }\n \n /* Specialized button styles */\n #plugincontainer .translate-field-btn {\n background-color: var(--greyBackgroundColor, #6c757d);\n font-size: 0.8em;\n width: auto;\n padding: 2px 5px;\n margin-left: 5px;\n min-width: unset;\n }\n \n #plugincontainer .translate-field-btn:hover {\n background-color: var(--secondaryColor, #5a6268);\n }\n \n #plugincontainer #triggerDetail {\n background-color: var(--primary, var(--mainColor));\n border: 1px solid var(--primary, var(--mainColor));\n border-radius: 4px;\n padding: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n #plugincontainer #triggerDetail svg {\n fill: var(--on-primary, var(--mainForegroundColor));\n stroke: var(--on-primary, var(--mainForegroundColor));\n }\n \n #plugincontainer .edit-icon path {\n stroke: var(--on-primary, var(--mainForegroundColor));\n }\n \n /* Loading Circle Indicator */\n #plugincontainer .loading-circle {\n display: flex; \n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1000;\n background-color: rgba(255, 255, 255, 0.7);\n border-radius: 50%;\n width: 80px;\n height: 80px;\n justify-content: center;\n align-items: center;\n }\n \n #plugincontainer .spinner {\n border: 5px solid rgba(0, 0, 0, 0.1);\n width: 50px;\n height: 50px;\n border-radius: 50%;\n border-left-color: var(--primary, var(--mainColor));\n animation: spin 1s linear infinite;\n }\n \n @keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n\n /* Pagination styles */\n #plugincontainer #pageButtonsContainer {\n margin: 15px 0;\n text-align: center;\n display: flex;\n justify-content: center;\n align-items: center;\n flex-wrap: wrap;\n gap: 5px;\n }\n \n #plugincontainer .page-button {\n background-color: var(--primary, var(--mainColor));\n min-width: 40px;\n height: 40px;\n padding: 5px 10px;\n margin: 0 2px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n }\n \n #plugincontainer .current-page-button {\n background-color: var(--secondaryColor);\n font-weight: bold;\n }\n \n #plugincontainer .page-info {\n margin-left: 10px;\n font-size: 14px;\n color: var(--greyForegroundColor, #666);\n }\n \n /* Confirmation Modal Styles */\n #plugincontainer .modal {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(0,0,0,0.5);\n display: none;\n justify-content: center;\n align-items: center;\n z-index: 1000;\n }\n \n #plugincontainer .modal-content {\n background-color: var(--backgroundPrimary, white);\n padding: 20px;\n border-radius: 8px;\n width: 400px;\n text-align: center;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);\n position: relative;\n }\n \n #plugincontainer .modal-content h3 {\n margin-top: 0;\n color: var(--mainColor);\n font-size: 1.4em;\n margin-bottom: 15px;\n }\n \n #plugincontainer .modal-content p {\n margin-bottom: 20px;\n font-size: 16px;\n line-height: 1.5;\n }\n \n #plugincontainer .modal-buttons {\n display: flex;\n justify-content: center;\n gap: 15px;\n }\n \n #plugincontainer #confirmButton {\n background-color: var(--secondaryColor, #d9534f);\n border-color: var(--secondaryColor, #d9534f);\n }\n \n #plugincontainer #cancelButton {\n background-color: var(--greyBackgroundColor, #6c757d);\n border-color: var(--greyBackgroundColor, #6c757d);\n }\n \n #plugincontainer #confirmationBox {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n background-color: var(--primary, var(--mainColor));\n padding: 20px;\n border-radius: 5px;\n }\n \n #plugincontainer #confirmationBox p {\n margin-bottom: 20px;\n color: var(--on-primary, var(--mainForegroundColor));\n }\n \n #plugincontainer #confirmationBox button {\n margin-right: 10px;\n padding: 8px 16px;\n border: none;\n border-radius: 3px;\n background-color: var(--on-primary, var(--mainForegroundColor));\n color: var(--primary, var(--mainColor));\n cursor: pointer;\n }\n \n /* Action buttons and Header Styles */\n #plugincontainer .action-column-header {\n padding: 0;\n }\n \n #plugincontainer .action-headers-container {\n display: flex;\n justify-content: space-between;\n width: 100%;\n }\n \n #plugincontainer .action-header {\n flex: 1;\n text-align: center;\n font-size: 0.9em;\n font-weight: bold;\n padding: 8px 4px;\n white-space: nowrap;\n }\n \n #plugincontainer .action-buttons-row {\n display: flex;\n justify-content: space-between;\n width: 100%;\n }\n \n #plugincontainer .action-cell {\n flex: 1;\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 4px;\n }\n \n #plugincontainer .action-button.label-xl {\n font-size: 90%;\n padding: var(--input-y-padding) calc(var(--input-x-padding) / 2) !important;\n }\n \n #plugincontainer .counter-label {\n font-size: 0.75em;\n margin-top: 4px;\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n \n /* Language notice styles */\n #plugincontainer .language-notice {\n margin: 10px 0;\n padding: 10px;\n border-radius: 4px;\n }\n \n #plugincontainer .language-notice.success {\n background-color: #e6ffe6;\n border: 1px solid #b3ffb3;\n }\n \n #plugincontainer .language-notice.warning {\n background-color: #fff8e6;\n border: 1px solid #ffe0b3;\n }\n \n #plugincontainer .language-notice p {\n margin: 0;\n font-size: 14px;\n }\n \n /* Field container styles */\n #plugincontainer .field-container {\n display: flex;\n align-items: center;\n width: 100%;\n }\n \n #plugincontainer .field-container input,\n #plugincontainer .field-container textarea {\n flex: 1;\n min-width: 200px;\n }\n \n /* For the translation status colors */\n #plugincontainer input[style*="background-color: #e6ffe6"],\n #plugincontainer textarea[style*="background-color: #e6ffe6"] {\n background-color: #e6ffe6 !important;\n }\n \n #plugincontainer input[style*="background-color: #ffe6e6"],\n #plugincontainer textarea[style*="background-color: #ffe6e6"] {\n background-color: #ffe6e6 !important;\n }\n \n #plugincontainer input[style*="background-color: #fff8e6"],\n #plugincontainer textarea[style*="background-color: #fff8e6"] {\n background-color: #fff8e6 !important;\n }\n \n /* Additional styles for making table fade when loading */\n #plugincontainer #myTable {\n transition: opacity 0.3s ease;\n }\n \n #plugincontainer #myTable.loading {\n opacity: 0.5;\n pointer-events: none;\n }\n \n /* Responsive styles for different screen sizes */\n @media (max-width: 768px) {\n #plugincontainer .page-button {\n min-width: 32px;\n height: 32px;\n font-size: 12px;\n padding: 3px 6px;\n }\n \n #plugincontainer .page-info {\n display: block;\n width: 100%;\n margin-top: 10px;\n text-align: center;\n }\n \n #plugincontainer table th,\n #plugincontainer table td {\n padding: 8px 10px;\n }\n \n #plugincontainer .action-button {\n width: 48px;\n height: 48px;\n }\n \n #plugincontainer .modal-content {\n width: 90%;\n max-width: 400px;\n }\n }\n '}function Z(){return'<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" class="edit-icon">\n <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/>\n </svg>'}async function _(){await v(0,window.videosPerPage)}}})}export{mt as register};