Skip to content

Commit

Permalink
Issue #501 Fix (#576)
Browse files Browse the repository at this point in the history
* Show search results

* Select songs from search results

* Added hymnary

* Updated toast message and added error handling.
  • Loading branch information
jzongker authored Jun 12, 2024
1 parent 40418b8 commit dc50c04
Show file tree
Hide file tree
Showing 17 changed files with 297 additions and 25 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
"@mapbox/node-pre-gyp": "^1.0.11",
"@sveltejs/svelte-virtual-list": "^3.0.1",
"@vimeo/player": "^2.16.4",
"axios": "^1.7.2",
"chord-transposer": "^3.0.9",
"cross-env": "^7.0.3",
"electron-store": "^8.0.1",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@
"no_name": "No name",
"media_replaced": "Missing media file replaced with match.",
"lyrics_undefined": "Could not find any lyrics!",
"lyrics_copied": "Lyrics copied from Genius!",
"lyrics_copied": "Lyrics copied from ",
"no_pdf_linux": "Can't export as PDF on Linux.",
"one_output": "You have to have at least one active output!",
"empty_cache": "Cache is empty.",
Expand Down
8 changes: 6 additions & 2 deletions public/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@
"no_name": "No name",
"media_replaced": "Missing media file replaced with match.",
"lyrics_undefined": "Could not find any lyrics!",
"lyrics_copied": "Lyrics copied from Genius!",
"lyrics_copied": "Lyrics copied from ",
"no_pdf_linux": "Can't export as PDF on Linux.",
"one_output": "You have to have at least one active output!",
"empty_cache": "Cache is empty.",
Expand Down Expand Up @@ -438,7 +438,11 @@
"lyrics": "Lyrics view",
"text": "Text edit",
"update": "Update show",
"slide_template": "Slide template"
"slide_template": "Slide template",
"search_results": "Search Results",
"source": "Source",
"artist": "Artist",
"song": "Song"
},
"actions": {
"rename": "Rename",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/en_GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@
"no_name": "No name",
"media_replaced": "Missing media file replaced with match.",
"lyrics_undefined": "Could not find any lyrics!",
"lyrics_copied": "Lyrics copied from Genius!",
"lyrics_copied": "Lyrics copied from ",
"no_pdf_linux": "Can't export as PDF on Linux.",
"one_output": "You have to have at least one active output!",
"empty_cache": "Cache is empty.",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/en_ZM.json
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@
"no_name": "No name",
"media_replaced": "Missing media file replaced with match.",
"lyrics_undefined": "Could not find any lyrics!",
"lyrics_copied": "Lyrics copied from Genius!",
"lyrics_copied": "Lyrics copied from ",
"no_pdf_linux": "Can't export as PDF on Linux.",
"one_output": "You have to have at least one active output!",
"empty_cache": "Cache is empty.",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@
"no_name": "No name",
"media_replaced": "Missing media file replaced with match.",
"lyrics_undefined": "Could not find any lyrics!",
"lyrics_copied": "Lyrics copied from Genius!",
"lyrics_copied": "Lyrics copied from ",
"no_pdf_linux": "Can't export as PDF on Linux.",
"one_output": "You have to have at least one active output!",
"empty_cache": "Cache is empty.",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@
"no_name": "Nessun nome",
"media_replaced": "Missing media file replaced with match.",
"lyrics_undefined": "Impossibile trovare alcun testo!",
"lyrics_copied": "Testi copiati da Genius!",
"lyrics_copied": "Testi copiati da ",
"no_pdf_linux": "Impossibile esportare come PDF su Linux.",
"one_output": "Devi avere almeno un output attivo!",
"empty_cache": "La cache è vuota.",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/no.json
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@
"no_name": "Ingen navn",
"media_replaced": "Manglende mediefil erstattet med match.",
"lyrics_undefined": "Kunne ikke finne noen sangtekster!",
"lyrics_copied": "Sangtekst kopiert fra Genius!",
"lyrics_copied": "Sangtekst kopiert fra ",
"no_pdf_linux": "Kan ikke eksportere som PDF på Linux.",
"one_output": "Du må ha minst en aktiv utgang!",
"empty_cache": "Hurtigbuffer er tom.",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@
"no_name": "Brak nazwy",
"media_replaced": "Brakujący plik zastąpiony pasującym.",
"lyrics_undefined": "Nie znaleziono słów do pieśni!",
"lyrics_copied": "Słowa pieśni skopiowano z Genius!",
"lyrics_copied": "Słowa pieśni skopiowano z ",
"no_pdf_linux": "Nie można wyeksportować PDF na Linuksie",
"one_output": "Musisz mieć co najmniej jedno aktywne wyjście!",
"empty_cache": "Pamięć podręczna jest pusta.",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/pt_BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@
"no_name": "No name",
"media_replaced": "Missing media file replaced with match.",
"lyrics_undefined": "Could not find any lyrics!",
"lyrics_copied": "Lyrics copied from Genius!",
"lyrics_copied": "Lyrics copied from ",
"no_pdf_linux": "Can't export as PDF on Linux.",
"one_output": "You have to have at least one active output!",
"empty_cache": "Cache is empty.",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@
"no_name": "Нет имени",
"media_replaced": "Отсутствующий файл мультимедиа заменен на совпадение.",
"lyrics_undefined": "Не могу найти слова!",
"lyrics_copied": "Текст песни скопирован с Genius!",
"lyrics_copied": "Текст песни скопирован с ",
"no_pdf_linux": "Невозможно экспортировать как PDF в Linux.",
"one_output": "У вас должен быть хотя бы один активный выход!",
"empty_cache": "Кэш пуст.",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/sk.json
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@
"no_name": "Žiadny názov",
"media_replaced": "Chýbajúci media súbor nahradený iným.",
"lyrics_undefined": "Nenašli sa žiadne texty!",
"lyrics_copied": "Texty skopírované z Genius!",
"lyrics_copied": "Texty skopírované z ",
"no_pdf_linux": "Nedá sa exportovať PDF na Linuxe.",
"one_output": "Musíte mať aspoň jeden aktívny výstup!",
"empty_cache": "Cache je prázdna.",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/sr.json
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@
"no_name": "No name",
"media_replaced": "Missing media file replaced with match.",
"lyrics_undefined": "Could not find any lyrics!",
"lyrics_copied": "Lyrics copied from Genius!",
"lyrics_copied": "Lyrics copied from ",
"no_pdf_linux": "Can't export as PDF on Linux.",
"one_output": "You have to have at least one active output!",
"empty_cache": "Cache is empty.",
Expand Down
2 changes: 1 addition & 1 deletion public/lang/ua.json
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@
"no_name": "Без імені",
"media_replaced": "Відсутній мультимедійний файл замінено відповідним.",
"lyrics_undefined": "Не вдалося знайти тексти!",
"lyrics_copied": "Текст пісні скопійовано з Genius!",
"lyrics_copied": "Текст пісні скопійовано з ",
"no_pdf_linux": "Неможливо експортувати як PDF у Linux.",
"one_output": "Ви повинні мати принаймні один активний вихід!",
"empty_cache": "Кеш порожній.",
Expand Down
153 changes: 153 additions & 0 deletions src/electron/utils/LyricSearch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import axios from "axios"

export type LyricSearchResult = {
source: string,
key: string,
artist: string,
title: string
originalQuery?: string
}

export class LyricSearch {



static search = async (artist:string, title: string) => {
const results = await Promise.all([
LyricSearch.searchGenius(artist, title),
LyricSearch.searchHymnary(title)
])
return results.flat()
}

static get(song:LyricSearchResult) {
if (song.source === "Genius") return LyricSearch.getGenius(song)
else if (song.source === "Hymnary") return LyricSearch.getHymnary(song)
return Promise.resolve("")
}


//GENIUS
private static getGeniusClient = () => {
const Genius = require("genius-lyrics")
return new Genius.Client()
}

private static searchGenius = async (artist:string, title: string) => {
try {
const client = this.getGeniusClient()
const songs = await client.songs.search(title + artist)
if (songs.length>3) songs.splice(3, songs.length-3)
return songs.map((s:any) => LyricSearch.convertGenuisToResult(s, title + artist));
} catch (ex) {
console.log(ex);
return []
}
}

//Would greatly prefer to just load via url or id, but the api fails often with these methods (malformed json)
private static getGenius = async (song:LyricSearchResult) => {
const client = this.getGeniusClient()
const songs = await client.songs.search(song.originalQuery || "")
let result = "";
for (let i = 0; i < songs.length; i++) {
if (songs[i].id.toString() === song.key) {
result = await songs[i].lyrics()
break
}
}
return result
}

private static convertGenuisToResult = (geniusResult:any, originalQuery:string) => {
return {
source: "Genius",
key: geniusResult.id.toString(),
artist: geniusResult.artist.name,
title: geniusResult.title,
originalQuery: originalQuery
} as LyricSearchResult
}

//HYMNARY
private static searchHymnary = async (title: string) => {
try {
const url = `https://hymnary.org/search?qu=%20tuneTitle%3A${encodeURIComponent(title)}%20media%3Atext%20in%3Atexts&export=csv`
const response = await axios.get(url)
const csv = await response.data
const songs = LyricSearch.CSVToArray(csv, ",")
if (songs.length>0) songs.splice(0, 1)
for (let i=songs.length-1; i>=0; i--) if (songs[i].length<7) songs.splice(i, 1)
if (songs.length>3) songs.splice(3, songs.length-3)
return songs.map((s:any) => LyricSearch.convertHymnaryToResult(s, title));
} catch (ex) {
console.log(ex);
return []
}
}

private static getHymnary = async (song:LyricSearchResult) => {
const url = `https://hymnary.org/text/${song.key}`
const response = await axios.get(url)
const html = await response.data
const regex = /<div property=\"text\">(.*?)<\/div>/sg
const match = regex.exec(html)

let result = ""
if (match) {
result = match[0]
result = result.replaceAll("</p>", "\n\n")
result = result.replace(/<[^>]*>?/gm, '');

const lines = result.split("\n")
const newLines:any[] = []
lines.forEach((line, idx) => {
if (idx<lines.length-3)
{
let contents = line.replace(/^\d+\s+/gm, ''); //remove leading numbers
newLines.push(contents)
}
});
result = newLines.join("\n")
}

return result
}

private static convertHymnaryToResult = (hymnaryResult:any, originalQuery:string) => {
return {
source: "Hymnary",
key: hymnaryResult[4],
artist: hymnaryResult[6],
title: hymnaryResult[0],
originalQuery: originalQuery
} as LyricSearchResult
}

// ref: http://stackoverflow.com/a/1293163/2343
// This will parse a delimited string into an array of
// arrays. The default delimiter is the comma, but this
// can be overriden in the second argument.
static CSVToArray( strData:string, strDelimiter:string ){
strDelimiter = (strDelimiter || ",");

var objPattern = new RegExp((
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
"([^\"\\" + strDelimiter + "\\r\\n]*))"
), "gi");

var arrData:any[] = [[]];
var arrMatches = null;
while (arrMatches = objPattern.exec( strData )){
var strMatchedDelimiter = arrMatches[ 1 ];
if (strMatchedDelimiter.length && strMatchedDelimiter !== strDelimiter) { arrData.push( [] ); }
var strMatchedValue;
if (arrMatches[ 2 ]) strMatchedValue = arrMatches[ 2 ].replace(new RegExp( "\"\"", "g" ), "\"");
else strMatchedValue = arrMatches[ 3 ];
arrData[ arrData.length - 1 ].push( strMatchedValue );
}
return( arrData );
}

}
20 changes: 11 additions & 9 deletions src/electron/utils/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { outputWindows } from "../output/output"
import { error_log } from "../data/store"
import { startRestListener, startWebSocket, stopApiListener } from "./api"
import checkForUpdates from "./updater"
import { LyricSearch } from "./LyricSearch"

// IMPORT
export function startImport(_e: any, msg: Message) {
Expand Down Expand Up @@ -115,6 +116,7 @@ const mainResponses: any = {
SHOWS_PATH: (): string => getDocumentsFolder(),
DATA_PATH: (): string => getDocumentsFolder(null, ""),
DISPLAY: (): boolean => false,
GET_LYRICS: (data: any): void => { getLyrics(data) },
GET_MIDI_OUTPUTS: (): string[] => getMidiOutputs(),
GET_MIDI_INPUTS: (): string[] => getMidiInputs(),
GET_SCREENS: (): void => getScreens(),
Expand All @@ -127,9 +129,7 @@ const mainResponses: any = {
MAXIMIZED: (): boolean => !!mainWindow?.isMaximized(),
MINIMIZE: (): void => mainWindow?.minimize(),
FULLSCREEN: (): void => mainWindow?.setFullScreen(!mainWindow?.isFullScreen()),
SEARCH_LYRICS: (data: any): void => {
searchLyrics(data)
},
SEARCH_LYRICS: (data: any): void => { searchLyrics(data) },
SEND_MIDI: (data: any): void => {
sendMidi(data)
},
Expand Down Expand Up @@ -277,13 +277,15 @@ function loadFonts() {

// SEARCH_LYRICS
async function searchLyrics({ artist, title }: any) {
const Genius = require("genius-lyrics")
const Client = new Genius.Client()

const songs = await Client.songs.search(title + artist)
const lyrics = songs[0] ? await songs[0].lyrics() : ""
const songs = await LyricSearch.search(artist, title)
toApp("MAIN", { channel: "SEARCH_LYRICS", data: songs })
}

toApp("MAIN", { channel: "SEARCH_LYRICS", data: { lyrics } })
// GET_LYRICS
async function getLyrics({song}: any) {
const lyrics = await LyricSearch.get(song)
console.log("****LYRICS", lyrics)
toApp("MAIN", { channel: "GET_LYRICS", data: { lyrics, source:song.source } })
}

// GET_SCREENS | GET_WINDOWS
Expand Down
Loading

0 comments on commit dc50c04

Please sign in to comment.