Skip to content

Commit

Permalink
Remove tag: prefix used with female or male
Browse files Browse the repository at this point in the history
  • Loading branch information
violet-dev committed Sep 1, 2024
1 parent b21b779 commit 66e2886
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 171 deletions.
41 changes: 4 additions & 37 deletions violet/lib/component/hitomi/displayed_tag.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,18 @@
import 'package:violet/component/hitomi/tag_translate.dart';

class DisplayedTag {
// artist, group, tag, series, character, uploader, type, class, language, prefix, page
// artist, group, tag, series, character, uploader, type, class, language, prefix, page, female, male
String? group;
// <tag>, female:<tag>, male:<tag>
// <tag>
String? name;
// <translated-tag>
String? translated;

// tag := <group>:<name>
DisplayedTag({String? tag, this.group, this.name, this.translated}) {
if (tag != null) {
final maybeGroup = tag.split(':').first;
if ([
'artist',
'group',
'tag',
'series',
'character',
'uploader',
'type',
'class',
'language',
'prefix',
'page',
].contains(maybeGroup)) {
group = maybeGroup;
name = tag.substring(tag.indexOf(':') + 1);
} else if (['female', 'male'].contains(maybeGroup)) {
group = 'tag';
name = tag;
}
}

if (group != null) {
if (['female', 'male'].contains(group)) {
if (!name!.startsWith('$group:')) name = '$group:$name';
group = 'tag';
}
group = tag.split(':').first;
name = tag.substring(tag.indexOf(':') + 1);
}
}

Expand All @@ -61,12 +36,4 @@ class DisplayedTag {
String toString() {
return getTag();
}

// TODO: https://github.com/project-violet/violet/issues/440 로 삭제
bool groupEqualTo(String otherGroup) {
if (otherGroup == 'female' || otherGroup == 'male') {
return group == 'tag' && name!.startsWith(otherGroup);
}
return group == otherGroup;
}
}
137 changes: 43 additions & 94 deletions violet/lib/component/hitomi/hitomi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import 'dart:convert';
import 'dart:io';

import 'package:get/get.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:tuple/tuple.dart';
Expand Down Expand Up @@ -46,8 +47,6 @@ class HitomiManager {

static String normalizeTagPrefix(String pp) {
switch (pp) {
case 'female':
case 'male':
case 'tags':
return 'tag';

Expand Down Expand Up @@ -86,6 +85,24 @@ class HitomiManager {
final text = path.readAsStringSync();
tagmap = jsonDecode(text);
}

// split `tag:female:` and `tag:male:` to `female:` and `male:`
if (tagmap!.containsKey('tag')) {
final tags = tagmap!['tag'] as Map<String, dynamic>;
final femaleTags = tags.entries
.where((e) => e.key.startsWith('female:'))
.map((e) => MapEntry(e.key.split(':')[1], e.value))
.toList();
final maleTags = tags.entries
.where((e) => e.key.startsWith('male:'))
.map((e) => MapEntry(e.key.split(':')[1], e.value))
.toList();
tagmap!['female'] = Map.fromEntries(femaleTags);
tagmap!['male'] = Map.fromEntries(maleTags);

tags.removeWhere(
(tag, _) => tag.startsWith('female:') || tag.startsWith('male:'));
}
}
}

Expand All @@ -108,44 +125,20 @@ class HitomiManager {
String prefix, bool useTranslated) {
final groupOrig = prefix.split(':')[0];
final group = normalizeTagPrefix(groupOrig);
final name = prefix.split(':').last;

final results = <Tuple2<DisplayedTag, int>>[];
if (!tagmap!.containsKey(group)) return results;

final nameCountsMap = tagmap![group] as Map<dynamic, dynamic>;
if (!useTranslated) {
final tagContains = () {
switch (groupOrig) {
case 'female':
case 'male':
return (key) =>
key.toLowerCase().startsWith('$groupOrig:') &&
key.toLowerCase().contains(prefix);

case 'tag':
final po = prefix.split(':')[1];
return (key) =>
!key.toLowerCase().startsWith('female:') &&
!key.toLowerCase().startsWith('male:') &&
key.toLowerCase().contains(po);

default:
final po = prefix.split(':')[1];
return (key) => key.toLowerCase().contains(po) as bool;
}
}();

nameCountsMap.entries
.where((element) => tagContains(element.key))
.forEach((element) {
results.add(Tuple2<DisplayedTag, int>(
DisplayedTag(group: group, name: element.key), element.value));
});
results.addAll(nameCountsMap.entries
.where((e) => e.key.toString().toLowerCase().contains(name))
.map((e) => Tuple2<DisplayedTag, int>(
DisplayedTag(group: group, name: e.key), e.value)));
} else {
final name = prefix.split(':').last;
results.addAll(TagTranslate.containsTotal(name)
.where((e) =>
e.groupEqualTo(groupOrig) && nameCountsMap.containsKey(e.name))
.where((e) => e.group! == group && nameCountsMap.containsKey(e.name))
.map((e) => Tuple2<DisplayedTag, int>(e, nameCountsMap[e.name])));
}
results.sort((a, b) => b.item2.compareTo(a.item2));
Expand Down Expand Up @@ -203,53 +196,28 @@ class HitomiManager {
if (prefix.contains(':')) {
final groupOrig = prefix.split(':')[0];
final group = normalizeTagPrefix(groupOrig);
final name = prefix.split(':').last;

// <Tag, Similarity, Count>
final results = <Tuple3<DisplayedTag, int, int>>[];
if (!tagmap!.containsKey(group)) return <Tuple2<DisplayedTag, int>>[];

final nameCountsMap = tagmap![group];
if (!useTranslated) {
if (groupOrig == 'female' || groupOrig == 'male') {
nameCountsMap.forEach((key, value) {
if (key.toLowerCase().startsWith('$groupOrig:')) {
results.add(Tuple3<DisplayedTag, int, int>(
DisplayedTag(group: groupOrig, name: key),
Distance.levenshteinDistance(
prefix.runes.toList(), key.runes.toList()),
value));
}
});
} else if (groupOrig == 'tag') {
// CHECK: tag:female:~, tag:artist:~도 허용해야하는지?
final name = prefix.split(':').last;
nameCountsMap.forEach((key, value) {
if (!key.toLowerCase().startsWith('female:') &&
!key.toLowerCase().startsWith('male:')) {
results.add(Tuple3<DisplayedTag, int, int>(
DisplayedTag(group: groupOrig, name: key),
Distance.levenshteinDistance(
name.runes.toList(), key.runes.toList()),
value));
}
});
} else {
final name = prefix.split(':').last;
nameCountsMap.forEach((key, value) {
results.add(Tuple3<DisplayedTag, int, int>(
DisplayedTag(group: group, name: key),
Distance.levenshteinDistance(
name.runes.toList(), key.runes.toList()),
value));
});
}
nameCountsMap.forEach((key, value) {
results.add(Tuple3<DisplayedTag, int, int>(
DisplayedTag(group: group, name: key),
Distance.levenshteinDistance(
name.runes.toList(), key.runes.toList()),
value));
});
} else {
final name = prefix.split(':').last;
results.addAll(TagTranslate.containsFuzzingTotal(name)
.where((e) =>
e.item1.groupEqualTo(groupOrig) &&
e.item1.group! == group &&
nameCountsMap.containsKey(e.item1.name))
.map((e) => Tuple3<DisplayedTag, int, int>(
e.item1, nameCountsMap[e.item1.name], e.item2)));
e.item1, e.item2, nameCountsMap[e.item1.name])));
}
results.sort((a, b) => a.item2.compareTo(b.item2));
return results
Expand All @@ -259,32 +227,13 @@ class HitomiManager {
if (!useTranslated) {
final results = <Tuple3<DisplayedTag, int, int>>[];
tagmap!.forEach((group, value) {
if (group == 'tag') {
value.forEach((name, count) {
if (name.contains(':')) {
final split = name.split(':');
results.add(Tuple3<DisplayedTag, int, int>(
DisplayedTag(group: split[0], name: name),
Distance.levenshteinDistance(
prefix.runes.toList(), split[1].runes.toList()),
count));
} else {
results.add(Tuple3<DisplayedTag, int, int>(
DisplayedTag(group: 'tag', name: name),
Distance.levenshteinDistance(
prefix.runes.toList(), name.runes.toList()),
count));
}
});
} else {
value.forEach((name, count) {
results.add(Tuple3<DisplayedTag, int, int>(
DisplayedTag(group: group, name: name),
Distance.levenshteinDistance(
prefix.runes.toList(), name.runes.toList()),
count));
});
}
value.forEach((name, count) {
results.add(Tuple3<DisplayedTag, int, int>(
DisplayedTag(group: group, name: name),
Distance.levenshteinDistance(
prefix.runes.toList(), name.runes.toList()),
count));
});
});
results.sort((a, b) => a.item2.compareTo(b.item2));
return results
Expand Down
40 changes: 19 additions & 21 deletions violet/lib/pages/search/search_bar_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,9 @@ class _SearchBarPageState extends State<SearchBarPage>
? token.split(':').last.replaceAll('_', ' ')
: token.replaceAll('_', ' '))
.map((e) => Tuple2<DisplayedTag, int>(
DisplayedTag(group: 'tag', name: e.item1),
DisplayedTag(
group: e.item1.split(':').first,
name: e.item1.split(':').last),
(e.item2 * 100).toInt()))
.toList();
} else if (token.startsWith('series:')) {
Expand Down Expand Up @@ -785,14 +787,12 @@ class _SearchBarPageState extends State<SearchBarPage>
}

if (info.item2 > 0 && Settings.searchShowCount) {
count =
' (${info.item2.toString() + (related && info.item1.group == 'tag' ? '%' : '')})';
count = ' (${info.item2.toString() + (related ? '%' : '')})';
}

if (info.item1.group == 'tag' && info.item1.name!.startsWith('female:')) {
if (info.item1.group == 'female') {
color = Colors.pink;
} else if (info.item1.group == 'tag' &&
info.item1.name!.startsWith('male:')) {
} else if (info.item1.group == 'male') {
color = Colors.blue;
} else if (info.item1.group == 'prefix') {
color = Colors.orange;
Expand Down Expand Up @@ -884,11 +884,7 @@ class _SearchBarPageState extends State<SearchBarPage>
labelPadding: const EdgeInsets.all(0.0),
avatar: CircleAvatar(
backgroundColor: Colors.grey.shade600,
child: Text(info.item1.group == 'tag' &&
(info.item1.name!.startsWith('female:') ||
info.item1.name!.startsWith('male:'))
? info.item1.name![0].toUpperCase()
: info.item1.group![0].toUpperCase()),
child: Text(info.item1.group![0].toUpperCase()),
),
label: RichText(
text: TextSpan(
Expand All @@ -907,12 +903,7 @@ class _SearchBarPageState extends State<SearchBarPage>
onPressed: () async {
// Insert text to cursor.
if (info.item1.group != 'prefix') {
var insert = (info.item1.group == 'tag' &&
(info.item1.name!.startsWith('female') ||
info.item1.name!.startsWith('male'))
? info.item1.name
: info.item1.getTag())!
.replaceAll(' ', '_');
final insert = info.item1.getTag().replaceAll(' ', '_');

_searchController.text = _searchText!.substring(0, _insertPos) +
insert +
Expand All @@ -923,11 +914,18 @@ class _SearchBarPageState extends State<SearchBarPage>
extentOffset: _insertPos! + insert.length,
);

if (info.item1.group == 'tag') {
_relatedLists = HitomiIndexs.getRelatedTag(
info.item1.name!.replaceAll('_', ' '))
if (info.item1.group == 'tag' ||
info.item1.group == 'female' ||
info.item1.group == 'male') {
_relatedLists = HitomiIndexs.getRelatedTag(info.item1.group == 'tag'
? info.item1.name!.replaceAll('_', ' ')
: info.item1.getTag().replaceAll('_', ' '))
.map((e) => Tuple2<DisplayedTag, int>(
DisplayedTag(group: 'tag', name: e.item1),
DisplayedTag(
group: e.item1.contains(':')
? e.item1.split(':').first
: 'tag',
name: e.item1.split(':').last),
(e.item2 * 100).toInt()))
.toList();
setState(() {});
Expand Down
22 changes: 7 additions & 15 deletions violet/lib/pages/settings/tag_selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,11 @@ class _TagSelectorDialogState extends State<TagSelectorDialog> {

if (info.item2 > 0 && _showCount) count = ' (${info.item2})';

if (info.item1.group == 'tag' && info.item1.name!.startsWith('female:')) {
print(info.item1);

if (info.item1.group == 'female') {
color = Colors.pink;
} else if (info.item1.group == 'tag' &&
info.item1.name!.startsWith('male:')) {
} else if (info.item1.group == 'male') {
color = Colors.blue;
} else if (info.item1.group == 'prefix') {
color = Colors.orange;
Expand All @@ -244,15 +245,11 @@ class _TagSelectorDialogState extends State<TagSelectorDialog> {
color = Colors.orange;
}

var fc = RawChip(
final fc = RawChip(
labelPadding: const EdgeInsets.all(0.0),
avatar: CircleAvatar(
backgroundColor: Colors.grey.shade600,
child: Text(info.item1.group == 'tag' &&
(info.item1.name!.startsWith('female:') ||
info.item1.name!.startsWith('male:'))
? info.item1.name![0].toUpperCase()
: info.item1.group![0].toUpperCase()),
child: Text(info.item1.group![0].toUpperCase()),
),
label: Text(
' $tagDisplayed$count',
Expand All @@ -267,12 +264,7 @@ class _TagSelectorDialogState extends State<TagSelectorDialog> {
onPressed: () async {
// Insert text to cursor.
if (info.item1.group != 'prefix') {
var insert = (info.item1.group == 'tag' &&
(info.item1.name!.startsWith('female') ||
info.item1.name!.startsWith('male'))
? info.item1.name
: info.item1.getTag())!
.replaceAll(' ', '_');
final insert = info.item1.getTag().replaceAll(' ', '_');

_searchController.text = _searchText!.substring(0, _insertPos) +
insert +
Expand Down
Loading

0 comments on commit 66e2886

Please sign in to comment.