feat: add improve name button

This commit is contained in:
Louis Heredero 2025-04-30 11:33:55 +02:00
parent 8fbe5ae3c4
commit 2afecd1c04
Signed by: HEL
GPG Key ID: 8D83DE470F8544E7
8 changed files with 323 additions and 22 deletions

View File

@ -9,6 +9,10 @@
<script src="/static/js/edit.mjs" type="module"></script> <script src="/static/js/edit.mjs" type="module"></script>
</head> </head>
<body> <body>
<button id="improve-btn" class="template improve">
<img src="/static/images/improve.svg">
<img class="clicked" src="/static/images/improve_clicked.svg">
</button>
<header id="topbar"> <header id="topbar">
<nav> <nav>

View File

@ -7,3 +7,7 @@
body { body {
font-family: Ubuntu; font-family: Ubuntu;
} }
.template {
display: none !important;
}

View File

@ -28,6 +28,7 @@ table {
td { td {
text-align: center; text-align: center;
position: relative;
} }
} }
} }
@ -104,6 +105,76 @@ label {
cursor: pointer; cursor: pointer;
} }
button.improve {
width: 2em;
height: 2em;
border: none;
margin: 0;
padding: 0;
cursor: pointer;
position: absolute;
top: 50%;
transform: translateY(-50%);
margin-left: 0.4em;
border-radius: 0.4em;
&:hover{
background-color: #8d8d8d42;
}
img {
position: absolute;
inset: 0;
width: inherit;
height: inherit;
object-fit: contain;
}
.clicked {
opacity: 0;
transition: opacity 0.2s;
}
&.clicked {
.clicked {
opacity: 1;
}
}
/*background: url("/static/images/improve.svg");
background-size: contain;
width: 2em;
height: 2em;
border: none;
margin: 0;
padding: 0;
cursor: pointer;
position: absolute;
top: 50%;
transform: translateY(-50%);
margin-left: 0.4em;
border-radius: 0.4em;
&:hover{
background-color: #8d8d8d42;
}
&::after {
content: "";
position: absolute;
background: url("/static/images/improve_clicked.svg");
background-size: contain;
width: inherit;
height: inherit;
position: absolute;
inset: 0;
opacity: 0;
transition: opacity 0.2s;
}
&.clicked {
&::after {
opacity: 1;
}
}*/
}
.popup { .popup {
display: grid; display: grid;
place-items: center; place-items: center;
@ -238,6 +309,9 @@ label {
align-items: center; align-items: center;
gap: 0.2em; gap: 0.2em;
} }
}
}
}
.select { .select {
border: solid black 1px; border: solid black 1px;
@ -245,6 +319,3 @@ label {
background-color: #fafafa; background-color: #fafafa;
} }
} }
}
}
}

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64"
height="64"
viewBox="0 0 64 64"
version="1.1"
id="svg1"
inkscape:version="1.4.1 (1:1.4.1+202503302257+93de688d07)"
sodipodi:docname="improve.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="true"
inkscape:zoom="8.8461329"
inkscape:cx="18.652218"
inkscape:cy="27.808761"
inkscape:window-width="2048"
inkscape:window-height="1228"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
id="grid1"
units="px"
originx="0"
originy="0"
spacingx="1"
spacingy="1"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="8"
enabled="true"
visible="true" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g1"
transform="matrix(2,0,0,2,-30,-24)">
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 24,32 c 3,0 8,-5 8,-8 0,3 5,8 8,8 -3,0 -8,5 -8,8 0,-3 -5,-8 -8,-8 z"
id="path1"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.7;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 19,22 c 1.875,0 5,-3.125 5,-5 0,1.875 3.125,5 5,5 -1.875,0 -5,3.125 -5,5 0,-1.875 -3.125,-5 -5,-5 z"
id="path1-3"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 35,19 c 1.125,0 3,-1.875 3,-3 0,1.125 1.875,3 3,3 -1.125,0 -3,1.875 -3,3 0,-1.125 -1.875,-3 -3,-3 z"
id="path1-1"
sodipodi:nodetypes="ccccc" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64"
height="64"
viewBox="0 0 64 64"
version="1.1"
id="svg1"
inkscape:version="1.4.1 (1:1.4.1+202503302257+93de688d07)"
sodipodi:docname="improve_clicked.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="true"
inkscape:zoom="8.8461329"
inkscape:cx="18.652218"
inkscape:cy="27.808761"
inkscape:window-width="2048"
inkscape:window-height="1228"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
id="grid1"
units="px"
originx="0"
originy="0"
spacingx="1"
spacingy="1"
empcolor="#0099e5"
empopacity="0.30196078"
color="#0099e5"
opacity="0.14901961"
empspacing="8"
enabled="true"
visible="true" />
</sodipodi:namedview>
<defs
id="defs1" />
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g1"
transform="matrix(2,0,0,2,-30,-24)"
style="fill:#efe348;fill-opacity:1">
<path
style="fill:#efe348;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
d="m 24,32 c 3,0 8,-5 8,-8 0,3 5,8 8,8 -3,0 -8,5 -8,8 0,-3 -5,-8 -8,-8 z"
id="path1"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#efe348;stroke:#000000;stroke-width:0.7;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
d="m 19,22 c 1.875,0 5,-3.125 5,-5 0,1.875 3.125,5 5,5 -1.875,0 -5,3.125 -5,5 0,-1.875 -3.125,-5 -5,-5 z"
id="path1-3"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#efe348;stroke:#000000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
d="m 35,19 c 1.125,0 3,-1.875 3,-3 0,1.125 1.875,3 3,3 -1.125,0 -3,1.875 -3,3 0,-1.125 -1.875,-3 -3,-3 z"
id="path1-1"
sodipodi:nodetypes="ccccc" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -18,6 +18,29 @@ const CorrectionType = {
FIELD: "field" FIELD: "field"
} }
const WORDS = {
forced: {
default: "Forced",
fre: "Forcés",
"fre-ca": "Forcés"
},
full: {
default: "Full",
fre: "Complets",
"fre-ca": "Complets"
},
}
function containsWord(parts, word) {
return Object.values(WORDS[word]).some(w => parts.includes(w))
}
function getWord(word, lang) {
const words = WORDS[word]
return words[lang] ?? words.default
}
class MismatchCorrection { class MismatchCorrection {
/** /**
* *
@ -183,8 +206,13 @@ export default class IntegrityManager {
case "subtitle": case "subtitle":
const stLang = findLanguage(lower) const stLang = findLanguage(lower)
if (stLang !== null) {fields.language = stLang} if (stLang !== null) {fields.language = stLang}
const forced = parts.includes("forced") const isForced = containsWord(parts, "forced")
if (forced) {fields.flags.forced = forced} const isFull = containsWord(parts, "full")
if (isForced) {
fields.flags.forced = true
} else if (isFull) {
fields.flags.forced = false
}
const sdh = parts.includes("sdh") const sdh = parts.includes("sdh")
if (sdh) {fields.flags.hearing_impaired = sdh} if (sdh) {fields.flags.hearing_impaired = sdh}
@ -261,20 +289,23 @@ export default class IntegrityManager {
case "audio": case "audio":
if (fields.flags.original) { if (fields.flags.original) {
name += " VO" name += " VO"
} else if (fields.language === "fr") { }/* else if (fields.language === "fre") {
name += " VFF" name += " VFF"
} else if (fields.language === "fr-ca") { } else if (fields.language === "fre-ca") {
name =+ " VFQ" name += " VFQ"
}*/
if (fields.flags.visual_impaired) {
name += " AD"
} }
if (fields.channels) { if (fields.channels) {
name += " : " + fields.channels name += " / " + fields.channels
} }
break break
case "subtitle": case "subtitle":
if (fields.flags.forced) { if (fields.flags.forced) {
name += " Forced" name += " " + getWord("forced", fields.language)
} else { } else {
name += " Full" name += " " + getWord("full", fields.language)
} }
if (fields.flags.hearing_impaired) { if (fields.flags.hearing_impaired) {
name += " SDH" name += " SDH"
@ -314,4 +345,20 @@ export default class IntegrityManager {
} }
return input return input
} }
/**
*
* @param {Track} track
*/
improveName(track) {
let nameFields = this.parseName(track.table.type, track.fields["name"])
const keys = Object.keys(flattenObj(nameFields))
Object.entries(flattenObj(track.fields)).forEach(([key, val]) => {
if (!keys.includes(key)) {
updateObjectFromJoinedKey(nameFields, key, val)
}
})
const name = this.reconstructName(track.table.type, nameFields)
track.editValue("name", name)
}
} }

View File

@ -19,8 +19,20 @@ export class Track {
this.row.dataset.i = this.idx this.row.dataset.i = this.idx
this.table.fields.forEach(field => { this.table.fields.forEach(field => {
const td = this.row.insertCell(-1) const td = this.row.insertCell(-1)
const input = this.makeInput(field, this.fields[field.key], this.idx) const input = this.makeInput(field, this.fields[field.key])
td.appendChild(input) td.appendChild(input)
if (field.key === "name") {
const btn = document.getElementById("improve-btn").cloneNode(true)
btn.id = null
btn.classList.remove("template")
btn.addEventListener("click", () => {
this.improveName()
btn.classList.add("clicked")
setTimeout(() => btn.classList.remove("clicked"), 1000)
})
td.appendChild(btn)
}
}) })
return this.row return this.row
} }
@ -111,6 +123,10 @@ export class Track {
break break
} }
} }
improveName() {
this.table.editor.integrity_mgr.improveName(this)
}
} }
export default class TracksTable { export default class TracksTable {

View File

@ -29,22 +29,22 @@ export const LANGUAGES = {
"fre": { "fre": {
display: "Français FR", display: "Français FR",
code: "fr", code: "fr",
aliases: ["fr", "fre", "fra", "french", "francais", "français", "vf", "vff", "france"] aliases: ["fr", "fra", "french", "francais", "français", "vf", "vff", "france"]
}, },
"eng": { "eng": {
display: "English", display: "English",
code: "gb", code: "gb",
aliases: ["en", "eng", "ang", "english", "anglais", "uk", "gb", "usa", "british", "american", "amérique", "amerique", "angleterre", "royaume-uni"] aliases: ["en", "ang", "english", "anglais", "uk", "gb", "usa", "british", "american", "amérique", "amerique", "angleterre", "royaume-uni"]
}, },
"deu": { "deu": {
display: "Deutsch", display: "Deutsch",
code: "de", code: "de",
aliases: ["de", "deu", "ger", "german", "allemand", "deutsch", "germany", "allemagne"] aliases: ["de", "ger", "german", "allemand", "deutsch", "germany", "allemagne"]
}, },
"kor": { "kor": {
display: "Korean", display: "Korean",
code: "kr", code: "kr",
aliases: ["ko", "kr", "kor", "cor", "korean", "coreen", "coréen", "corée", "coree", "korea"] aliases: ["ko", "kr", "cor", "korean", "coreen", "coréen", "corée", "coree", "korea"]
}, },
"jpn": { "jpn": {
display: "Japanese", display: "Japanese",
@ -54,7 +54,7 @@ export const LANGUAGES = {
"tur": { "tur": {
display: "Turkish", display: "Turkish",
code: "tr", code: "tr",
aliases: ["tu", "tr", "tur", "tür", "turkish", "turc", "turquie"] aliases: ["tu", "tr", "tür", "turkish", "turc", "turquie"]
}, },
"und": { "und": {
display: "Undefined", display: "Undefined",
@ -63,6 +63,10 @@ export const LANGUAGES = {
} }
} }
export function getLanguageAliases(langTag) {
return (langTag === "und" ? [] : [langTag]).concat(LANGUAGES[langTag].aliases)
}
/** /**
* Tries to find a language name in the given string * Tries to find a language name in the given string
* @param {string} value The string in which to search for a language * @param {string} value The string in which to search for a language
@ -70,7 +74,7 @@ export const LANGUAGES = {
*/ */
export function findLanguage(value) { export function findLanguage(value) {
for (const lang in LANGUAGES) { for (const lang in LANGUAGES) {
const aliases = LANGUAGES[lang].aliases const aliases = getLanguageAliases(lang)
const matches = aliases.map(a => { const matches = aliases.map(a => {
return new RegExp("\\b" + a + "\\b").test(value) return new RegExp("\\b" + a + "\\b").test(value)
}) })
@ -82,7 +86,7 @@ export function findLanguage(value) {
} }
export function isLanguageTagAlias(langTag, value) { export function isLanguageTagAlias(langTag, value) {
return LANGUAGES[langTag].aliases.includes(value) return getLanguageAliases(langTag).includes(value)
} }
export function updateObjectFromJoinedKey(obj, joinedKey, value) { export function updateObjectFromJoinedKey(obj, joinedKey, value) {