This commit is contained in:
Darklyter 2025-12-01 19:52:48 -08:00 committed by GitHub
commit 8fae716707
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 94 additions and 5 deletions

View file

@ -217,6 +217,69 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
}
}
function translateScrapedMeasurements(scrapedMeasurements?: string) {
if (!scrapedMeasurements) {
return;
}
// Check for autoConvert setting in Settings->Interface->Editing
const autoConvert = stashConfig?.ui.autoConvertMetricMeasurements ?? '';
if (!autoConvert){
return scrapedMeasurements
}
// A lot of JAV sites list measurements as "B90 W80 H90", so if that's there convert it to ##-##-## format
const javMeasurements = scrapedMeasurements.replace(/[^0-9BWH]+/g, '').toUpperCase();
const javPattern = /^B(\d+)W(\d+)H(\d+)$/;
const javMatch = javMeasurements.match(javPattern);
if (javMatch){
const javBust = parseInt(javMatch[1]);
const JavWaist = parseInt(javMatch[2]);
const JavHips = parseInt(javMatch[3]);
scrapedMeasurements = `${javBust}-${JavWaist}-${JavHips}`;
}
// Strip out all invalid characters for measurements
scrapedMeasurements = scrapedMeasurements.replace('/[^0-9A-Z-\/ ]+/g', '');
// Define the regex pattern for measurements (e.g., "90D-85-90")
const pattern = /^(\d+)([A-Z]+)?[-\/ ](\d+)[-\/ ](\d+)$/;
const upperMeasurements = scrapedMeasurements.toUpperCase();
const match = upperMeasurements.match(pattern);
if (!match) {
return upperMeasurements;
}
// With regex group matches, set values to groups
const bust = parseInt(match[1]);
const cupSize = match[2] || ''; // Cup size is optional
const waist = parseInt(match[3]);
const hips = parseInt(match[4]);
if (bust > 50 && waist > 45 && hips > 50) {
// Convert centimeters to inches
const cmToInches = (cm: number) => Math.round(cm * 0.393701);
const bustInches = cmToInches(bust);
const waistInches = cmToInches(waist);
const hipsInches = cmToInches(hips);
// Convert European cup sizes to US standard
let newCupsize = cupSize;
if (newCupsize) {
const stringPairs = [['A', 'AA'], ['B', 'A'], ['C', 'B'], ['D', 'C'], ['E', 'D'], ['F', 'DD'], ['G', 'E'], ['H', 'F'], ['I', 'G'], ['J', 'H'], ['K', 'I']];
const matchedPair = stringPairs.find(([firstString]) => firstString === newCupsize);
newCupsize = matchedPair ? matchedPair[1] : newCupsize;
}
// Create the result string in the same format
const resultString = `${bustInches}${newCupsize}-${waistInches}-${hipsInches}`;
return resultString;
}
return upperMeasurements;
}
function updatePerformerEditStateFromScraper(
state: Partial<GQL.ScrapedPerformerDataFragment>
) {
@ -248,7 +311,11 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
formik.setFieldValue("height_cm", parseInt(state.height, 10));
}
if (state.measurements) {
formik.setFieldValue("measurements", state.measurements);
// measurements is a string in the scraper data
const newMeasurements = translateScrapedMeasurements(state.measurements);
if (newMeasurements) {
formik.setFieldValue("measurements", newMeasurements);
}
}
if (state.fake_tits) {
formik.setFieldValue("fake_tits", state.fake_tits);
@ -679,6 +746,16 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
return renderField("tag_ids", title, tagsControl());
}
function renderMeasurements() {
const newMeasurements = translateScrapedMeasurements(formik.values.measurements);
if (newMeasurements){
if (formik.values.measurements != newMeasurements){
formik.setFieldValue("measurements", newMeasurements)
}
}
return renderInputField("measurements");
}
return (
<>
{renderScrapeModal()}
@ -724,7 +801,7 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
{renderSelectField("circumcised", stringCircumMap)}
{renderInputField("measurements")}
{renderMeasurements()}
{renderInputField("fake_tits")}
{renderInputField("tattoos", "textarea")}

View file

@ -521,8 +521,7 @@ export const SettingsInterfacePanel: React.FC = PatchComponent(
</option>
))}
</SelectSetting>
</SettingSection>
</SettingSection>
<SettingSection headingID="config.ui.image_lightbox.heading">
<NumberSetting
headingID="config.ui.slideshow_delay.heading"
@ -778,6 +777,13 @@ export const SettingsInterfacePanel: React.FC = PatchComponent(
))}
</SelectSetting>
)}
<BooleanSetting
id="auto_convert_metric_measurements"
headingID="config.ui.editing.auto_convert_metric_measurements.heading"
subHeadingID="config.ui.editing.auto_convert_metric_measurements.description"
checked={ui.autoConvertMetricMeasurements ?? undefined}
onChange={(v) => saveUI({ autoConvertMetricMeasurements: v })}
/>
</SettingSection>
<SettingSection headingID="config.ui.custom_css.heading">

View file

@ -62,6 +62,8 @@ export interface IUIConfig {
enableTagBackgroundImage?: boolean;
// if true view expanded details compact
compactExpandedDetails?: boolean;
// if true measurements > 50-45-50 will be converted into US (Imperial) values
autoConvertMetricMeasurements?: boolean;
// if true show all content details by default
showAllDetails?: boolean;

View file

@ -677,7 +677,11 @@
"stars": "Stars"
}
}
}
},
"auto_convert_metric_measurements": {
"description": "When enabled, this option will auto-convert metric measurements into US (Inches) for values > 50-45-50 (In Performer Edit)",
"heading": "Auto Convert Metric Measurements"
}
},
"funscript_offset": {
"description": "Time offset in milliseconds for interactive scripts playback.",