v7.0.1
This commit is contained in:
+21
-35
@@ -5,7 +5,6 @@ import (
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Hiragana to Romaji mapping
|
||||
var hiraganaToRomaji = map[rune]string{
|
||||
'あ': "a", 'い': "i", 'う': "u", 'え': "e", 'お': "o",
|
||||
'か': "ka", 'き': "ki", 'く': "ku", 'け': "ke", 'こ': "ko",
|
||||
@@ -17,20 +16,19 @@ var hiraganaToRomaji = map[rune]string{
|
||||
'や': "ya", 'ゆ': "yu", 'よ': "yo",
|
||||
'ら': "ra", 'り': "ri", 'る': "ru", 'れ': "re", 'ろ': "ro",
|
||||
'わ': "wa", 'を': "wo", 'ん': "n",
|
||||
// Dakuten (voiced)
|
||||
|
||||
'が': "ga", 'ぎ': "gi", 'ぐ': "gu", 'げ': "ge", 'ご': "go",
|
||||
'ざ': "za", 'じ': "ji", 'ず': "zu", 'ぜ': "ze", 'ぞ': "zo",
|
||||
'だ': "da", 'ぢ': "ji", 'づ': "zu", 'で': "de", 'ど': "do",
|
||||
'ば': "ba", 'び': "bi", 'ぶ': "bu", 'べ': "be", 'ぼ': "bo",
|
||||
// Handakuten (semi-voiced)
|
||||
|
||||
'ぱ': "pa", 'ぴ': "pi", 'ぷ': "pu", 'ぺ': "pe", 'ぽ': "po",
|
||||
// Small characters
|
||||
|
||||
'ゃ': "ya", 'ゅ': "yu", 'ょ': "yo",
|
||||
'っ': "", // Double consonant marker
|
||||
'っ': "",
|
||||
'ぁ': "a", 'ぃ': "i", 'ぅ': "u", 'ぇ': "e", 'ぉ': "o",
|
||||
}
|
||||
|
||||
// Katakana to Romaji mapping
|
||||
var katakanaToRomaji = map[rune]string{
|
||||
'ア': "a", 'イ': "i", 'ウ': "u", 'エ': "e", 'オ': "o",
|
||||
'カ': "ka", 'キ': "ki", 'ク': "ku", 'ケ': "ke", 'コ': "ko",
|
||||
@@ -42,23 +40,22 @@ var katakanaToRomaji = map[rune]string{
|
||||
'ヤ': "ya", 'ユ': "yu", 'ヨ': "yo",
|
||||
'ラ': "ra", 'リ': "ri", 'ル': "ru", 'レ': "re", 'ロ': "ro",
|
||||
'ワ': "wa", 'ヲ': "wo", 'ン': "n",
|
||||
// Dakuten (voiced)
|
||||
|
||||
'ガ': "ga", 'ギ': "gi", 'グ': "gu", 'ゲ': "ge", 'ゴ': "go",
|
||||
'ザ': "za", 'ジ': "ji", 'ズ': "zu", 'ゼ': "ze", 'ゾ': "zo",
|
||||
'ダ': "da", 'ヂ': "ji", 'ヅ': "zu", 'デ': "de", 'ド': "do",
|
||||
'バ': "ba", 'ビ': "bi", 'ブ': "bu", 'ベ': "be", 'ボ': "bo",
|
||||
// Handakuten (semi-voiced)
|
||||
|
||||
'パ': "pa", 'ピ': "pi", 'プ': "pu", 'ペ': "pe", 'ポ': "po",
|
||||
// Small characters
|
||||
|
||||
'ャ': "ya", 'ュ': "yu", 'ョ': "yo",
|
||||
'ッ': "", // Double consonant marker
|
||||
'ッ': "",
|
||||
'ァ': "a", 'ィ': "i", 'ゥ': "u", 'ェ': "e", 'ォ': "o",
|
||||
// Extended katakana
|
||||
'ー': "", // Long vowel mark
|
||||
|
||||
'ー': "",
|
||||
'ヴ': "vu",
|
||||
}
|
||||
|
||||
// Combination mappings for きゃ, しゃ, etc.
|
||||
var combinationHiragana = map[string]string{
|
||||
"きゃ": "kya", "きゅ": "kyu", "きょ": "kyo",
|
||||
"しゃ": "sha", "しゅ": "shu", "しょ": "sho",
|
||||
@@ -85,13 +82,12 @@ var combinationKatakana = map[string]string{
|
||||
"ジャ": "ja", "ジュ": "ju", "ジョ": "jo",
|
||||
"ビャ": "bya", "ビュ": "byu", "ビョ": "byo",
|
||||
"ピャ": "pya", "ピュ": "pyu", "ピョ": "pyo",
|
||||
// Extended combinations
|
||||
|
||||
"ティ": "ti", "ディ": "di", "トゥ": "tu", "ドゥ": "du",
|
||||
"ファ": "fa", "フィ": "fi", "フェ": "fe", "フォ": "fo",
|
||||
"ウィ": "wi", "ウェ": "we", "ウォ": "wo",
|
||||
}
|
||||
|
||||
// ContainsJapanese checks if a string contains Japanese characters
|
||||
func ContainsJapanese(s string) bool {
|
||||
for _, r := range s {
|
||||
if isHiragana(r) || isKatakana(r) || isKanji(r) {
|
||||
@@ -110,12 +106,10 @@ func isKatakana(r rune) bool {
|
||||
}
|
||||
|
||||
func isKanji(r rune) bool {
|
||||
return (r >= 0x4E00 && r <= 0x9FFF) || // CJK Unified Ideographs
|
||||
(r >= 0x3400 && r <= 0x4DBF) // CJK Unified Ideographs Extension A
|
||||
return (r >= 0x4E00 && r <= 0x9FFF) ||
|
||||
(r >= 0x3400 && r <= 0x4DBF)
|
||||
}
|
||||
|
||||
// JapaneseToRomaji converts Japanese text (hiragana/katakana) to romaji
|
||||
// Note: Kanji cannot be converted without a dictionary, so they are kept as-is
|
||||
func JapaneseToRomaji(text string) string {
|
||||
if !ContainsJapanese(text) {
|
||||
return text
|
||||
@@ -126,7 +120,7 @@ func JapaneseToRomaji(text string) string {
|
||||
i := 0
|
||||
|
||||
for i < len(runes) {
|
||||
// Check for っ/ッ (double consonant)
|
||||
|
||||
if i < len(runes)-1 && (runes[i] == 'っ' || runes[i] == 'ッ') {
|
||||
nextRomaji := ""
|
||||
if romaji, ok := hiraganaToRomaji[runes[i+1]]; ok {
|
||||
@@ -135,13 +129,12 @@ func JapaneseToRomaji(text string) string {
|
||||
nextRomaji = romaji
|
||||
}
|
||||
if len(nextRomaji) > 0 {
|
||||
result.WriteByte(nextRomaji[0]) // Double the first consonant
|
||||
result.WriteByte(nextRomaji[0])
|
||||
}
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// Check for two-character combinations
|
||||
if i < len(runes)-1 {
|
||||
combo := string(runes[i : i+2])
|
||||
if romaji, ok := combinationHiragana[combo]; ok {
|
||||
@@ -156,17 +149,16 @@ func JapaneseToRomaji(text string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// Single character conversion
|
||||
r := runes[i]
|
||||
if romaji, ok := hiraganaToRomaji[r]; ok {
|
||||
result.WriteString(romaji)
|
||||
} else if romaji, ok := katakanaToRomaji[r]; ok {
|
||||
result.WriteString(romaji)
|
||||
} else if isKanji(r) {
|
||||
// Keep kanji as-is (would need dictionary for proper conversion)
|
||||
|
||||
result.WriteRune(r)
|
||||
} else {
|
||||
// Keep other characters (punctuation, spaces, etc.)
|
||||
|
||||
result.WriteRune(r)
|
||||
}
|
||||
i++
|
||||
@@ -175,21 +167,17 @@ func JapaneseToRomaji(text string) string {
|
||||
return result.String()
|
||||
}
|
||||
|
||||
// BuildSearchQuery creates a search query from track name and artist
|
||||
// Converts Japanese to romaji if present
|
||||
func BuildSearchQuery(trackName, artistName string) string {
|
||||
// Convert Japanese to romaji
|
||||
|
||||
trackRomaji := JapaneseToRomaji(trackName)
|
||||
artistRomaji := JapaneseToRomaji(artistName)
|
||||
|
||||
// Clean up the query - remove special characters that might interfere with search
|
||||
trackClean := cleanSearchQuery(trackRomaji)
|
||||
artistClean := cleanSearchQuery(artistRomaji)
|
||||
|
||||
return strings.TrimSpace(artistClean + " " + trackClean)
|
||||
}
|
||||
|
||||
// cleanSearchQuery removes special characters that might interfere with search
|
||||
func cleanSearchQuery(s string) string {
|
||||
var result strings.Builder
|
||||
for _, r := range s {
|
||||
@@ -202,21 +190,19 @@ func cleanSearchQuery(s string) string {
|
||||
return strings.TrimSpace(result.String())
|
||||
}
|
||||
|
||||
// cleanToASCII removes all non-ASCII characters and keeps only letters, numbers, spaces
|
||||
// This is useful for creating search queries that work better with Tidal's search
|
||||
func cleanToASCII(s string) string {
|
||||
var result strings.Builder
|
||||
for _, r := range s {
|
||||
// Keep only ASCII letters, numbers, spaces, and basic punctuation
|
||||
|
||||
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') ||
|
||||
(r >= '0' && r <= '9') || r == ' ' || r == '-' || r == '\'' {
|
||||
result.WriteRune(r)
|
||||
} else if r == ',' || r == '.' {
|
||||
// Convert punctuation to space
|
||||
|
||||
result.WriteRune(' ')
|
||||
}
|
||||
}
|
||||
// Clean up multiple spaces
|
||||
|
||||
cleaned := strings.Join(strings.Fields(result.String()), " ")
|
||||
return strings.TrimSpace(cleaned)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user