UNPKG

peertube-plugin-transposer-connector

Version:

Transposer connector is a PeerTube language tool plugin to transcribe and translate with Whisper

2 lines (1 loc) 38 kB
var xe=Object.defineProperty;var W=Object.getOwnPropertySymbols;var ke=Object.prototype.hasOwnProperty,Ce=Object.prototype.propertyIsEnumerable;var X=(f,c,u)=>c in f?xe(f,c,{enumerable:!0,configurable:!0,writable:!0,value:u}):f[c]=u,ee=(f,c)=>{for(var u in c||(c={}))ke.call(c,u)&&X(f,u,c[u]);if(W)for(var u of W(c))Ce.call(c,u)&&X(f,u,c[u]);return f};async function Se({registerClientRoute:f,peertubeHelpers:c}){let{notifier:u}=c;function $(){return window.location.origin}f({route:"/transposer",onMount:({rootEl:h})=>{window.currentPage=1,window.videosPerPage=10;let Le='<?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>',$e='<?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>',k='<?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>',te='<?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>',P='<?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>',Me='<?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>',Be='<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>',Ee='<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>';h.innerHTML=ne();let z=document.createElement("style");z.innerHTML=ce(),h.appendChild(z);let F=h.querySelector("#loadingIndicator");F&&(F.style.display="flex"),ge();function ne(){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 C(n=0,o=window.videosPerPage){let r=h.querySelector("#loadingIndicator");r.style.display="flex";let l=h.querySelector("#myTable");l.innerHTML="",l.classList.add("loading");var d=$();console.log(n),console.log(o);let e="".concat(d,"/api/v1/users/me/videos/?start=").concat(n,"&count=").concat(o);console.log(e);try{await fetch(e,{method:"GET",headers:c.getAuthHeader()}).then(a=>(console.log("api:",e),console.log("result:",a),a.json())).then(async a=>{var y,x;let t=h.querySelector("#messageContainer");if(a.total==0){t.textContent="No Videos yet",r.style.display="none",l.classList.remove("loading");return}a.total>0&&(t.textContent=""),window.totalVideos=a.total;let s=document.createElement("tbody"),m=document.createElement("tr");m.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 ',s.appendChild(m);for(let i of a.data){let p=i.id,ue=await fetch("".concat($(),"/api/v1/videos/").concat(p,"/captions"),{method:"GET",headers:c.getAuthHeader()}).then(g=>g.ok?g.json():(console.error("Failed to fetch captions: ".concat(g.status)),{total:0,data:[]})).catch(g=>(console.error("Error fetching captions: ".concat(g)),{total:0,data:[]})),M=await fetch("".concat(c.getBaseRouterRoute(),"/language/metadata/video/").concat(p),{headers:c.getAuthHeader()}).then(g=>g.ok?g.json():(console.error("Failed to fetch metadata: ".concat(g.status)),{})).catch(g=>(console.error("Error fetching metadata: ".concat(g)),{})),pe=Object.keys(M),D=new Set;pe.forEach(g=>{M[g]&&Object.keys(M[g]).forEach(R=>{M[g][R]&&M[g][R].trim()!==""&&D.add(R)})});let V=D.size;var v=ue.total;let H=v>0,ve=i.uuid,me=i.shortUUID,Te=i.state.label,q=i.language?i.language.label:null,he=i.language?i.language.id:null,fe=i.name,we=i.description,N=new Date(i.publishedAt),be="".concat(N.toLocaleDateString()," ").concat(N.toLocaleTimeString()),ye=i.thumbnailPath,O=i.url,S=!!(i.language&&i.language.id&&i.language.id!==null&&i.language.label&&i.language.label!=="Unknown");console.log("Video ".concat(p,': videoLanguage="').concat(q,'", videoLanguageId="').concat(he,'", hasLanguage=').concat(S,', language.id="').concat((y=i.language)==null?void 0:y.id,'", language.label="').concat((x=i.language)==null?void 0:x.label,'"'));let w;i.privacy&&typeof i.privacy.id<"u"?w=i.privacy.id:typeof i.privacy=="number"?w=i.privacy:(console.warn("Video ".concat(p,": Unknown privacy structure"),i.privacy),w=1);let _=w===1,Z=w===2,Y=w===3,J=w===4,I=i.passwordProtected===!0||i.hasPassword===!0,K=(_||Z)&&!I,G=!K;console.log("Video ".concat(p,": privacyId=").concat(w,", isPublic=").concat(_,", isUnlisted=").concat(Z,", isPrivate=").concat(Y,", isInternal=").concat(J,", hasPassword=").concat(I,", hasLanguage=").concat(S,", isAccessibleByPrivacy=").concat(K,", isRestricted=").concat(G));let B,E,T,j=!1,b="";S?G?(B="disabled",E=k,T="0/1",j=!0,I?b="Transcription is not available for password-protected videos. Please remove the password.":Y?b="Transcription is not available for private videos. Please make the video public or unlisted.":J?b="Transcription is not available for internal videos. Please make the video public or unlisted.":b="Transcription is not available for this video type. Please make the video public or unlisted."):H?(B="success",E=P,T="1/1",b="Video has already been transcribed"):(B="not-triggered",E=k,T="0/1",b="Click to transcribe video"):(B="not-triggered",E=k,T="0/1",j=!1,b="Click to set language and transcribe video");let Q=document.createElement("tr");s.appendChild(Q),Q.innerHTML='\n <div id="videoId" hidden>'.concat(p,'</div>\n <div id="videoUuid" hidden>').concat(ve,'</div>\n <div id="videoShortUuid" hidden>').concat(me,'</div>\n <div id="alreadyTranscripted-').concat(p,'" hidden>').concat(H,'</div>\n <div id="isRestricted-').concat(p,'" hidden>').concat(G,'</div>\n <div id="hasLanguage-').concat(p,'" hidden>').concat(S,'</div>\n <td id="formattedPublishedAtCell">').concat(be,'</td>\n <td id="thumbnailCell"><img src="').concat(ye,'" alt="Thumbnail" width="100" onclick="(function() {\n const videoUrl = \'').concat(O,'\';\n if (videoUrl) {\n window.open(videoUrl, \'_blank\');\n }\n })();"></td>\n <td id="titleCell" class="clickable-title" onclick="(function() {\n const videoUrl = \'').concat(O,"';\n if (videoUrl) {\n window.open(videoUrl, '_blank');\n }\n })();\" title=\"Click to open video\">").concat(fe,'</td>\n <td id="descriptionCell">').concat(we,'</td>\n <td id="languageCell">').concat(q||"No language set",'</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(p,'" class="action-button ').concat(B,'" \n ').concat(j?"disabled":"",' \n title="').concat(b,'">\n ').concat(E,'\n <span class="counter-label">').concat(T,'</span>\n </button>\n </div>\n <div class="action-cell">\n <button id="triggerTranslation" data-id="').concat(p,'" class="action-button ').concat(v>0?"success":"not-triggered",'">\n ').concat(v>0?P:k,'\n <span class="counter-label">').concat(v,'/26</span>\n </button>\n </div>\n <div class="action-cell">\n <button id="triggerMetadataTranslation" data-id="').concat(p,'" class="action-button ').concat(V>0?"success":"not-triggered",'">\n ').concat(V>0?P:k,'\n <span class="counter-label">').concat(V,'/26</span>\n </button>\n </div>\n <div class="action-cell">\n <button id="triggerDetail" data-id="').concat(p,'" class="action-button edit">\n ').concat(de(),"\n </button>\n </div>\n </div>\n</td>\n ")}l.appendChild(s),r.style.display="none",l.classList.remove("loading"),le(),se()}).catch(a=>{console.log("Error:",a),r.style.display="none",l.classList.remove("loading")})}catch(a){console.error("Error:",a),r.style.display="none",l.classList.remove("loading")}}let L=null;async function oe(n){console.log("Checking transcription for video ID:",n);var o=document.querySelector("#hasLanguage-".concat(n)),r=!1;if(o){let t=o.innerHTML.trim();r=t==="true",console.log("Video ".concat(n,': hasLanguageText="').concat(t,'", hasLanguage=').concat(r))}if(!r){console.log("Cannot transcribe video without language set");let t=document.getElementById("confirmationModal"),s=document.getElementById("confirmationMessage");s.textContent="A language must be selected for this video before transcription can be performed. Please edit the video and set a language first.";let m=document.getElementById("confirmButton");m.textContent="Edit Video";let v=document.getElementById("cancelButton");v.textContent="Cancel",t.style.display="flex";let y=()=>{t.style.display="none",A(n),m.removeEventListener("click",y),v.removeEventListener("click",x),t.removeEventListener("click",i)},x=()=>{t.style.display="none",m.removeEventListener("click",y),v.removeEventListener("click",x),t.removeEventListener("click",i)},i=p=>{p.target===t&&(t.style.display="none",m.removeEventListener("click",y),v.removeEventListener("click",x),t.removeEventListener("click",i))};m.addEventListener("click",y),v.addEventListener("click",x),t.addEventListener("click",i),v.focus();return}var l=document.querySelector("#isRestricted-".concat(n)),d=!1;if(l&&(d=l.innerHTML==="true"),d){console.log("Cannot transcribe restricted video (not public/unlisted or password-protected)"),u.error("Cannot transcribe restricted videos. Only public and unlisted videos without password protection can be transcribed.");return}var e=!1,a=document.querySelector("#alreadyTranscripted-".concat(n));if(a&&(e=a.innerHTML==="true"),!n||isNaN(n)){console.error("Invalid videoId provided"),u.error("Invalid video ID");return}if(e){console.log("Video already has transcription, showing confirmation dialog"),L=n;let t=document.getElementById("confirmationModal"),s=document.getElementById("confirmationMessage");s.textContent="There is already a transcription for this video. Do you want to overwrite it?";let m=document.getElementById("confirmButton");m.textContent="Yes, Overwrite";let v=document.getElementById("cancelButton");v.textContent="No, Cancel",t.style.display="flex",v.focus();return}U(n)}async function U(n){let o=document.querySelector('#triggerTranscription[data-id="'.concat(n,'"]'));if(o){let r=document.getElementById("confirmationModal"),l=document.getElementById("confirmationMessage");l.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",r.style.display="flex";let e=()=>{r.style.display="none",ie(n,o),d.removeEventListener("click",e),s.removeEventListener("click",a),r.removeEventListener("click",t)},a=()=>{r.style.display="none",d.removeEventListener("click",e),s.removeEventListener("click",a),r.removeEventListener("click",t)},t=m=>{m.target===r&&(r.style.display="none",d.removeEventListener("click",e),s.removeEventListener("click",a),r.removeEventListener("click",t))};d.addEventListener("click",e);let s=document.getElementById("cancelButton");s.addEventListener("click",a),r.addEventListener("click",t)}}async function ie(n,o){if(o){let r=o.innerHTML;o.innerHTML="".concat(te,'<span class="counter-label">Loading...</span>'),o.disabled=!0}try{let r=c.getAuthHeader(),l=await fetch("".concat(c.getBaseRouterRoute(),"/transposer/translate/").concat(n),{method:"POST",headers:ee({"Content-Type":"application/json"},r),body:JSON.stringify({})});if(!l.ok){let e=await l.text();throw new Error("Translation request failed: ".concat(l.status," ").concat(e))}let d=await l.json();console.log("Translation result:",d),u.success("Translation sent successfully - now wait until completed"),o&&(o.innerHTML="".concat(P,'<span class="counter-label">1/1</span>'),o.classList.remove("not-triggered"),o.classList.add("success"),o.disabled=!1)}catch(r){u.error("Error transcribing video: ".concat(r)),console.error("Error transcribing video:",r),o&&(o.innerHTML="".concat(k,'<span class="counter-label">0/1</span>'),o.disabled=!1)}}function ae(n){console.log("start translate all languages for Video",n),window.open("".concat($(),"/p/transposer/translate?videoId=").concat(n),"_self")}function re(n){console.log("start translate Metadata",n),window.open("".concat($(),"/p/transposer/translate/metadata?videoId=").concat(n),"_self")}function A(n){console.log("redirecting to video update page",n),window.open("".concat($(),"/videos/update/").concat(n),"_self")}function le(){h.querySelectorAll("#triggerTranscription").forEach(t=>{var s=t.dataset.id;t.addEventListener("click",()=>{t.disabled||t.classList.contains("disabled")||oe(s)})});let o=h.querySelectorAll("#triggerTranslation");console.log(o),o.forEach(t=>{console.log(t),t.addEventListener("click",()=>{let s=t.dataset.id;ae(s)})}),h.querySelectorAll("#triggerMetadataTranslation").forEach(t=>{t.addEventListener("click",()=>{let s=t.dataset.id;re(s)})}),h.querySelectorAll("#triggerDetail").forEach(t=>{t.addEventListener("click",()=>{let s=t.dataset.id;A(s)})});let d=document.getElementById("confirmButton"),e=document.getElementById("cancelButton"),a=document.getElementById("confirmationModal");d.addEventListener("click",()=>{L&&(U(L),L=null),a.style.display="none"}),e.addEventListener("click",()=>{console.log("Transcription cancelled by user"),L=null,a.style.display="none"}),a.addEventListener("click",t=>{t.target===a&&(L=null,a.style.display="none")})}function se(){let n=document.getElementById("pageButtonsContainer");n.innerHTML="";let o=window.currentPage;window.totalPages=Math.ceil(window.totalVideos/window.videosPerPage);let r=Math.max(1,o-2),l=Math.min(window.totalPages,r+4);if(l===window.totalPages&&(r=Math.max(1,l-4)),r>1){let e=document.createElement("button");e.textContent="\xAB",e.classList.add("page-button"),e.title="First page",e.addEventListener("click",async()=>{window.currentPage=1,await C(0,window.videosPerPage)}),n.appendChild(e)}if(o>1){let e=document.createElement("button");e.textContent="\u2039",e.classList.add("page-button"),e.title="Previous page",e.addEventListener("click",async()=>{window.currentPage=o-1,await C((window.currentPage-1)*window.videosPerPage,window.videosPerPage)}),n.appendChild(e)}for(let e=r;e<=l;e++){let a=document.createElement("button");a.textContent=e,a.classList.add("page-button"),a.disabled=e===o,e===o&&a.classList.add("current-page-button"),a.addEventListener("click",async()=>{e!==o&&(window.currentPage=e,await C((e-1)*window.videosPerPage,window.videosPerPage))}),n.appendChild(a)}if(o<window.totalPages){let e=document.createElement("button");e.textContent="\u203A",e.classList.add("page-button"),e.title="Next page",e.addEventListener("click",async()=>{window.currentPage=o+1,await C((window.currentPage-1)*window.videosPerPage,window.videosPerPage)}),n.appendChild(e)}if(l<window.totalPages){let e=document.createElement("button");e.textContent="\xBB",e.classList.add("page-button"),e.title="Last page",e.addEventListener("click",async()=>{window.currentPage=window.totalPages,await C((window.totalPages-1)*window.videosPerPage,window.videosPerPage)}),n.appendChild(e)}let d=document.createElement("span");d.classList.add("page-info"),d.textContent=" Page ".concat(o," of ").concat(window.totalPages," (").concat(window.totalVideos," videos) "),n.appendChild(d)}function ce(){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 /* Clickable title styling */\n #plugincontainer .clickable-title {\n cursor: pointer;\n color: var(--primary, var(--mainColor));\n text-decoration: underline;\n transition: color 0.3s ease;\n }\n\n #plugincontainer .clickable-title:hover {\n color: var(--secondaryColor, var(--mainColor));\n text-decoration: none;\n }\n\n /* Disabled action button styles */\n #plugincontainer .action-button.disabled {\n background-color: var(--greyBackgroundColor, #e9ecef);\n border-color: var(--greyForegroundColor, #ccc);\n color: var(--greyForegroundColor, #6c757d);\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n #plugincontainer .action-button.disabled:hover {\n background-color: var(--greyBackgroundColor, #e9ecef);\n cursor: not-allowed;\n }\n\n #plugincontainer .action-button.disabled svg {\n fill: var(--greyForegroundColor, #6c757d);\n stroke: var(--greyForegroundColor, #6c757d);\n opacity: 0.6;\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 de(){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 ge(){await C(0,window.videosPerPage)}}})}export{Se as register};