peertube-plugin-transposer-connector
Version:
Transposer connector is a PeerTube language tool plugin to transcribe and translate with Whisper
2 lines (1 loc) • 21.4 kB
JavaScript
var he=Object.defineProperty;var ae=Object.getOwnPropertySymbols;var ve=Object.prototype.hasOwnProperty,me=Object.prototype.propertyIsEnumerable;var oe=(q,v,m)=>v in q?he(q,v,{enumerable:!0,configurable:!0,writable:!0,value:m}):q[v]=m,re=(q,v)=>{for(var m in v||(v={}))ve.call(v,m)&&oe(q,m,v[m]);if(ae)for(var m of ae(v))me.call(v,m)&&oe(q,m,v[m]);return q};async function Te({registerClientRoute:q,peertubeHelpers:v}){let{notifier:m}=v;function W(){return window.location.origin}function ie(o){var k=window.location.href;o=o.replace(/[\[\]]/g,"\\$&");var g=new RegExp("[?&]"+o+"(=([^&#]*)|&|#|$)"),i=g.exec(k);return i?i[2]?decodeURIComponent(i[2].replace(/\+/g," ")):"":null}async function le(){try{let o=await fetch("".concat(W(),"/plugins/settings"));if(!o.ok)throw new Error("Failed to fetch settings: ".concat(o.status));return await o.json()}catch(o){return console.error("Error fetching plugin settings:",o),{}}}function X(o){return o==null?"":String(o)}async function R(o,k,g){try{let P=(await le())["trigger-transcription-and-translation"]||"https://api.transposer.eu",F="".concat(P,"/translate"),h=await fetch(F,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({input:o,source_language_id:k,target_language_ids:g})});if(!h.ok){let J=await h.text();throw new Error("Translation API error: ".concat(h.status," - ").concat(J))}return await h.json()}catch(i){throw console.error("Translation request failed: ".concat(i.message)),i}}q({route:"/transposer/translate/metadata",onMount:({rootEl:o})=>{o.innerHTML=Z();var k,g,i=null;let P=ie("videoId"),F=!1,I=null,h=!1;function Z(){return'\n <div id="plugincontainer">\n <h1>Translate Metadata</h1>\n <div id="languageNoticeContainer"></div>\n <button id="saveButton">Save Metadata</button><button id="backButton">Back</button><button id="translateEverything">Translate Everything</button><br><br>\n <div id="confirmationDialog" class="modal" style="display:none;">\n <div class="modal-content">\n <h3>Translation Options</h3>\n <p>How would you like to apply translations?</p>\n <button id="translateAll">Overwrite All</button>\n <button id="translateEmpty">Fill Empty Only</button>\n <button id="cancelTranslation">Cancel</button>\n </div>\n </div>\n <div id="unsavedChangesDialog" class="modal" style="display:none;">\n <div class="modal-content">\n <h3>Unsaved Changes</h3>\n <p>You have unsaved changes. Do you want to save them before leaving?</p>\n <button id="saveAndLeave">Save and Leave</button>\n <button id="leaveWithoutSaving">Leave Without Saving</button>\n <button id="stayOnPage">Stay on Page</button>\n </div>\n </div>\n </div>'}let J=o.querySelector("#saveButton");function C(n,s="info",l=3e3){I&&(clearTimeout(I),I=null),s==="success"?m.success(n):s==="error"?m.error(n):s==="warning"&&typeof m.warning=="function"?m.warning(n):m.info(n),I=setTimeout(()=>{I=null},l)}function ee(){if(F){console.log("Save already in progress, ignoring duplicate request");return}F=!0,console.log("Save Metadata into DB");let n={};if(k.querySelectorAll("tr").forEach(l=>{let f=l.querySelector("td:first-child").getAttribute("language-code"),x=l.querySelectorAll("td input, td textarea"),w=Array.from(x).map(u=>X(u.value));f!=null&&(n[f]={title:w[0],description:w[1],category:w[2],tags:w[3]})}),console.log("languageInputs",n),!P){console.error("Video ID not found in query parameters."),F=!1;return}fetch("".concat(v.getBaseRouterRoute(),"/language/metadata/video/").concat(P,"/metadata"),{method:"POST",headers:re({"Content-Type":"application/json"},v.getAuthHeader()),body:JSON.stringify(n)}).then(l=>{if(!l.ok)return l.text().then(c=>{throw console.error("Error response:",c),new Error("Failed to save metadata.")});C("Saved metadata successfully.","success"),h=!1}).catch(l=>{console.error("Error saving metadata:",l),C("Failed to save metadata.","error")}).finally(()=>{F=!1})}J.addEventListener("click",ee),o.querySelector("#backButton").addEventListener("click",()=>{console.log("back button clicked"),h?o.querySelector("#unsavedChangesDialog").style.display="block":Y()});function Y(){window.open("".concat(W(),"/p/transposer"),"_self")}o.querySelector("#saveAndLeave").addEventListener("click",()=>{ee(),o.querySelector("#unsavedChangesDialog").style.display="none",setTimeout(()=>{Y()},500)}),o.querySelector("#leaveWithoutSaving").addEventListener("click",()=>{o.querySelector("#unsavedChangesDialog").style.display="none",h=!1,Y()}),o.querySelector("#stayOnPage").addEventListener("click",()=>{o.querySelector("#unsavedChangesDialog").style.display="none"}),o.querySelector("#translateEverything").addEventListener("click",()=>{if(!i){C("No default language set. Please set a video language first.","error");return}let n=o.querySelector("#confirmationDialog");n.style.display="block"}),o.querySelector("#translateAll").addEventListener("click",()=>{te(!1),o.querySelector("#confirmationDialog").style.display="none"}),o.querySelector("#translateEmpty").addEventListener("click",()=>{te(!0),o.querySelector("#confirmationDialog").style.display="none"}),o.querySelector("#cancelTranslation").addEventListener("click",()=>{o.querySelector("#confirmationDialog").style.display="none"});function H(){return i?!0:(C("No default language set. Please set a video language first.","error"),!1)}async function te(n){var j,M,G,p,S,B,b,Q;if(!H())return;let s=k.querySelector("tr:first-child"),l=[];s.querySelectorAll("td").forEach((a,e)=>{e>0&&l.push(X(a.textContent))});let c=l[0],f=l[1],x=l[2],w=l[3];C("Starting translations...");let u=[],V=Array.from(k.querySelectorAll("tr")).slice(1);for(let a of V){let r=a.querySelector("td:first-child").getAttribute("language-code");r&&u.push(r)}let y={};if(u.forEach(a=>{y[a]={success:0,fail:0}}),c&&typeof c=="string"&&c.trim()!=="")try{let a=await R(c,i,u);for(let e of u){let r=T(e);if(!r)continue;let t=r.querySelector("td:nth-child(2) input");n&&t.value.trim()!==""||((M=(j=a==null?void 0:a.payload)==null?void 0:j[e])!=null&&M.text&&a.payload[e].success===!0?(t.value=a.payload[e].text,t.style.backgroundColor="#e6ffe6",y[e].success++,h=!0):(t.style.backgroundColor="#ffe6e6",y[e].fail++))}}catch(a){console.error("Error translating titles:",a);for(let e of u){let r=T(e);if(!r)continue;let t=r.querySelector("td:nth-child(2) input");n&&t.value.trim()!==""||(t.style.backgroundColor="#ffe6e6",y[e].fail++)}}if(f&&typeof f=="string"&&f.trim()!=="")try{let a=await R(f,i,u);for(let e of u){let r=T(e);if(!r)continue;let t=r.querySelector("td:nth-child(3) textarea");n&&t.value.trim()!==""||((p=(G=a==null?void 0:a.payload)==null?void 0:G[e])!=null&&p.text&&a.payload[e].success===!0?(t.value=a.payload[e].text,t.style.backgroundColor="#e6ffe6",y[e].success++,h=!0):(t.style.backgroundColor="#ffe6e6",y[e].fail++))}}catch(a){console.error("Error translating descriptions:",a);for(let e of u){let r=T(e);if(!r)continue;let t=r.querySelector("td:nth-child(3) textarea");n&&t.value.trim()!==""||(t.style.backgroundColor="#ffe6e6",y[e].fail++)}}if(x&&typeof x=="string"&&x.trim()!=="")try{let a=await R(x,i,u);for(let e of u){let r=T(e);if(!r)continue;let t=r.querySelector("td:nth-child(4) input");n&&t.value.trim()!==""||((B=(S=a==null?void 0:a.payload)==null?void 0:S[e])!=null&&B.text&&a.payload[e].success===!0?(t.value=a.payload[e].text,t.style.backgroundColor="#e6ffe6",y[e].success++,h=!0):(t.style.backgroundColor="#ffe6e6",y[e].fail++))}}catch(a){console.error("Error translating categories:",a);for(let e of u){let r=T(e);if(!r)continue;let t=r.querySelector("td:nth-child(4) input");n&&t.value.trim()!==""||(t.style.backgroundColor="#ffe6e6",y[e].fail++)}}if(w&&typeof w=="string"&&w.trim()!=="")try{let a=await R(w,i,u);for(let e of u){let r=T(e);if(!r)continue;let t=r.querySelector("td:nth-child(5) input");n&&t.value.trim()!==""||((Q=(b=a==null?void 0:a.payload)==null?void 0:b[e])!=null&&Q.text&&a.payload[e].success===!0?(t.value=a.payload[e].text,t.style.backgroundColor="#e6ffe6",y[e].success++,h=!0):(t.style.backgroundColor="#ffe6e6",y[e].fail++))}}catch(a){console.error("Error translating tags:",a);for(let e of u){let r=T(e);if(!r)continue;let t=r.querySelector("td:nth-child(5) input");n&&t.value.trim()!==""||(t.style.backgroundColor="#ffe6e6",y[e].fail++)}}let A=0,E=0,O=[];for(let a of u){let e=T(a);if(!e)continue;let r=e.querySelector("td:first-child").textContent,t=y[a].success,d=y[a].fail;A+=t,E+=d,(t>0||d>0)&&O.push({name:r,success:t,fail:d})}A>0&&E===0?C("Translations completed successfully for ".concat(O.length," languages!"),"success"):A>0&&E>0?C("Translations partially completed: ".concat(A," succeeded, ").concat(E," failed."),"warning"):E>0?C("All translations failed.","error"):C("No translations were performed.","info")}function T(n){let s=k.querySelectorAll("tr");for(let l of s){let c=l.querySelector("td:first-child");if(c&&c.getAttribute("language-code")===n)return l}return null}async function z(n,s,l,c){if(!H())return!1;try{if(s==null?s="":typeof s!="string"&&(s=String(s)),s.trim()==="")return n.style.backgroundColor="#ffe6e6",console.error("Cannot translate empty source text"),!1;n.style.backgroundColor="#fff8e6";let f=await R(s,l,[c]);return f&&f.payload&&f.payload[c]&&f.payload[c].text&&f.payload[c].success===!0?(n.value=f.payload[c].text,n.style.backgroundColor="#e6ffe6",h=!0,!0):(n.style.backgroundColor="#ffe6e6",console.error("Invalid translation result:",f),!1)}catch(f){return console.error("Translation error:",f),n.style.backgroundColor="#ffe6e6",!1}}function K(n){return n?n.label:""}function se(){let n=document.getElementById("languageNoticeContainer");n&&(i?n.innerHTML='\n <div class="language-notice success">\n <p>Default language for translations: <strong>'.concat(i,"</strong></p>\n </div>\n "):(n.innerHTML='\n <div class="language-notice warning">\n <p>\u26A0\uFE0F No default language set. Please set a video language first in the video settings.</p>\n </div>\n ',document.querySelectorAll(".translate-button, .translate-field-btn").forEach(l=>{l.disabled=!0,l.title="Set a video language first"}),document.getElementById("translateEverything").disabled=!0,document.getElementById("translateEverything").title="Set a video language first"))}function ce(){k.addEventListener("input",()=>{h=!0})}function ue(){window.addEventListener("beforeunload",n=>{if(h){let s="You have unsaved changes. Are you sure you want to leave?";return n.returnValue=s,s}})}function de(){fetch("".concat(W(),"/api/v1/videos/languages")).then(n=>n.json()).then(n=>{let s=["ar","bs","de","en","et","fr","it","hr","nl","pl","pt","ru","sr","sk","sl","es","cs","tr","uk","hu","bg","el","fi","he","ro","sv"];var l="".concat(W(),"/api/v1/videos/").concat(P);fetch(l,{method:"GET"}).then(c=>(console.log("api:",l),console.log("result:",c),c.json())).then(c=>{g=c,g&&g.language&&g.language.id?(i=g.language.id,console.log("Default language set to:",i)):(i=null,console.warn("No language found in video metadata")),se();for(let[x,w]of Object.entries(n))s.includes(x);let f="".concat(v.getBaseRouterRoute(),"/language/metadata/video/").concat(P);fetch(f,{method:"GET",headers:v.getAuthHeader()}).then(x=>(console.log("api:",f),console.log("result:",x),x.json())).then(x=>{console.log("languageMetadata",x);var w=["Title","Description","Category","Tags","Actions"],u=document.createElement("table"),V=document.createElement("thead");k=document.createElement("tbody");var y=document.createElement("tr"),A=document.createElement("th");A.textContent="Sprache",y.appendChild(A),w.forEach(function(p){var S=document.createElement("th");S.textContent=p,y.appendChild(S)}),V.appendChild(y);var E=document.createElement("tr"),O=document.createElement("td");O.textContent="Default",E.appendChild(O),w.forEach(function(p,S){var B=document.createElement("td");if(p==="Actions"){B.textContent="",E.appendChild(B);return}var b=g[p.toLowerCase()];p.toLowerCase()=="title"&&(b=g.name),p.toLowerCase()=="category"&&(b=K(g[p.toLowerCase()])),console.log(b),B.textContent=b||"",E.appendChild(B)}),k.appendChild(E);for(let[p,S]of Object.entries(n))if(s.includes(p)){var j=document.createElement("tr"),M=document.createElement("td");M.textContent=S,M.setAttribute("language-code",p),j.appendChild(M);let B=[];w.forEach(function(b,Q){var a=document.createElement("td");if(b==="Actions"){let t=document.createElement("div");t.className="translate-fields";let d=document.createElement("button");d.textContent="Translate All Fields",d.className="translate-button",d.setAttribute("data-lang",p),i||(d.disabled=!0,d.title="Set a video language first"),d.addEventListener("click",async()=>{if(!H())return;let $=g.name,ne=g.description,pe=K(g.category),ye=g.tags,L=B,U=!0,D=0,N=0;L[0]&&(await z(L[0],$,i,p)?D++:(U=!1,N++)),L[1]&&(await z(L[1],ne,i,p)?D++:(U=!1,N++)),L[2]&&(await z(L[2],pe,i,p)?D++:(U=!1,N++)),L[3]&&(await z(L[3],ye,i,p)?D++:(U=!1,N++)),U&&D>0?C("Translation for ".concat(S," completed successfully!"),"success"):D>0&&N>0?C("Translation for ".concat(S," partially completed (").concat(D," succeeded, ").concat(N," failed)."),"warning"):N>0?C("Translation for ".concat(S," failed."),"error"):C("No translations performed for ".concat(S,"."),"info")}),t.appendChild(d),a.appendChild(t)}else{var e;b==="Description"?e=document.createElement("textarea"):(e=document.createElement("input"),e.type="text"),e.style.minWidth="200px";let t=document.createElement("div");t.className="field-container",t.style.display="flex",t.style.alignItems="center";var r=x[b.toLowerCase()]&&x[b.toLowerCase()][p];e.value=r||"",e.addEventListener("input",()=>{h=!0}),t.appendChild(e);let d=document.createElement("button");d.textContent="T",d.title="Translate ".concat(b),d.className="translate-field-btn",d.style.marginLeft="5px",d.style.padding="2px 5px",i||(d.disabled=!0,d.title="Set a video language first"),d.addEventListener("click",async()=>{if(!H())return;let $="";switch(b){case"Title":$=g.name;break;case"Description":$=g.description;break;case"Category":$=K(g.category);break;case"Tags":$=g.tags;break}await z(e,$,i,p)?C("".concat(b," translated to ").concat(S),"success"):C("Failed to translate ".concat(b," to ").concat(S),"error")}),t.appendChild(d),a.appendChild(t),B.push(e)}j.appendChild(a)}),k.appendChild(j)}u.appendChild(V),u.appendChild(k);var G=document.getElementById("plugincontainer");G.appendChild(u),ce(),ue(),setTimeout(()=>{h=!1},500)})})})}function ge(){de();let n=document.createElement("style");n.innerHTML=fe(),o.appendChild(n)}function fe(){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 box-shadow: none;\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 #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 margin: 0 5px;\n transition: background-color 0.3s;\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 /* Specific button styles */\n #plugincontainer .translate-button {\n width: auto;\n }\n \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 }\n \n #plugincontainer .translate-field-btn:hover {\n background-color: var(--secondaryColor, #5a6268);\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 /* 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: flex;\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: 5px;\n width: 400px;\n text-align: center;\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n }\n \n #plugincontainer .modal-content h3 {\n margin-top: 0;\n color: var(--primary, var(--mainColor));\n }\n \n #plugincontainer .modal-content button {\n margin: 10px;\n padding: 10px 15px;\n }\n \n /* For the translate background 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 /* Unsaved changes dialog style */\n #plugincontainer #unsavedChangesDialog .modal-content {\n background-color: var(--backgroundPrimary, white);\n border: 2px solid var(--mainColor);\n }\n '}ge()}})}export{Te as register};