Created
November 11, 2013 17:41
-
-
Save phcostabh/7417157 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Lib Fuse | |
| var Fuse = require('./fuse.js'), | |
| // Lib http do Node | |
| http = require('http'), | |
| // Seta a url do Solr | |
| SOLR_HOST = process.argv[2].split(':')[0], | |
| // Seta porta do SOLR | |
| SOLR_PORT = parseInt(process.argv[2].split(':')[1] || 80, 10), | |
| // Flag de Debug | |
| DEBUG = parseInt(process.argv[3], 10) || false, | |
| matches, | |
| totalProcessed, | |
| musicListLength, | |
| streamContent = ''; | |
| // recuperar dados da stdin | |
| process.stdin.resume(); | |
| process.stdin.setEncoding('utf8'); | |
| process.stdin.on('data', function(chunk) { | |
| streamContent += chunk; | |
| }); | |
| process.stdin.on('end', function() { | |
| queryData(streamContent); | |
| streamContent = null; | |
| }); | |
| function queryData(data) { | |
| var singleQuery, | |
| pathSearch, | |
| partialPathSearch, | |
| currentItem, | |
| trash, | |
| queryBoost, | |
| queryOperator, | |
| i, | |
| searchTerm; | |
| matches = []; | |
| totalProcessed = 0; | |
| if (DEBUG) { | |
| console.error('DATA:', data); | |
| console.error('SOLR_HOST:', SOLR_HOST); | |
| console.error('SOLR_PORT:', SOLR_PORT); | |
| console.time('profile'); | |
| } | |
| try { | |
| // Transforma em objeto JS | |
| data = JSON.parse(data); | |
| singleQuery = false; | |
| } catch (ex) { | |
| singleQuery = true; | |
| data = [{ | |
| q: data | |
| }]; | |
| } | |
| // Lista de palavras a serem removidas do termo de busca | |
| trash = 'versão|versao|version|participacao|participação|acústico|acustico|acoustic|' + | |
| 'instrumental|live|track|album|remix|radio|rádio|bonus|bônus|estúdio|estudio|studio|' + | |
| 'feat\\.?|part\\.?|ao\\s?vivo|speech|com|soundtrack|faixa|official|oficial|Unplugged|HD|Cover|lyrics?'; | |
| if (singleQuery) { | |
| queryBoost = '{!boost%20b=log(h)}'; | |
| queryOperator = 'OR'; | |
| } else { | |
| queryBoost = ''; | |
| queryOperator = 'AND'; | |
| } | |
| // Estrutura inicial do path de busca | |
| partialPathSearch = '/solr/letras/select/?wt=json&rows=3&omitHeader=true&q=' + queryBoost + '{!lucene%20q.op=' + queryOperator + '%20df=full_txt}t:2' + '%20AND%20full_txt:'; | |
| musicListLength = data.length; | |
| for (i = musicListLength - 1; i >= 0; i--) { | |
| // Pega o objeto do item atual | |
| currentItem = data[i]; | |
| // Se não tiver query válida ou já possuir os itens cacheados, passa | |
| // pro próximo | |
| if (!currentItem.q || (currentItem.i && currentItem.d && currentItem.iar && currentItem.g)) { | |
| matches.push(currentItem); | |
| done(); | |
| continue; | |
| } | |
| searchTerm = currentItem.q | |
| .replace(/(\n|\r\n|\r)/g, '') | |
| // Remove possíveis formatos de arquivo de música | |
| .replace(/\.(3gp|act|AIFF|aac|ALAC|amr|atrac|Au|awb|dct|dss|dvf|flac|gsm|iklax|IVS|m4a|m4p|mmf|mp3|mpc|msv|ogg|Opus|ra|rm|raw|TTA|vox|wav|wma)$/, '') | |
| // Normaliza os espaços | |
| .replace(/\s{2,}/, ' ') | |
| // Trata strings começando com "track" ou "faixa", etc... | |
| .replace(/^((track|faixa).?\d{1,2})?/i, '') | |
| // Retira [...] e (...) que contenham palavras trash | |
| .replace(new RegExp('(?:[\\[(]).*(?=' + trash + ').*(?:[\\])])', 'gi'), '') | |
| // Normaliza os espaços novamente | |
| .replace(/\s{2,}/, ' ') | |
| // Escapa alguns caracteres p/ não bugar a busca no SOLR | |
| .replace('\\', '\\\\') | |
| .replace(/(\+|-|\||!|\(|\)|\{|\}|\[|\]|\^|~|\*|\?|:|"|;|\/)/g, "\\$&"); | |
| // Monta o path final do pacote HTTP | |
| pathSearch = partialPathSearch + encodeURIComponent(searchTerm); | |
| // Faz a busca no SOLR | |
| solrQuery(pathSearch, currentItem, singleQuery); | |
| } | |
| } | |
| /** | |
| * Condição de saída do programa | |
| * Checa se pode finalizar com sucesso ou erro | |
| * | |
| * @author Romano Augusto | |
| * @since 02/05/2013 | |
| * @param string [error] Mensagem de erro da requisição | |
| * http feita no Solr | |
| */ | |
| function done(error) { | |
| if (error) { | |
| if (DEBUG) { | |
| console.error('Saindo com erro:', error); | |
| console.timeEnd('profile'); | |
| } | |
| process.exit(1); | |
| } | |
| if (++totalProcessed === musicListLength) { | |
| console.log(JSON.stringify(matches)); | |
| if (DEBUG) { | |
| console.error('FIM'); | |
| console.timeEnd('profile'); | |
| } | |
| process.exit(0); | |
| } | |
| } | |
| function txt_tirar_acentos(s) { | |
| var re1 = /[ÁÀÂÃÄáàâãªä]/, | |
| re2 = /[ÉÈÊËéèêë&]/, | |
| re3 = /[óòôõöºÖÓÒÔÕ]/, | |
| re4 = /[úùûüÚÙÛÜ]/, | |
| re5 = /[íÍîïÏ]/; | |
| s = s.replace(re1, 'a') | |
| .replace(re2, 'e') | |
| .replace(re3, 'o') | |
| .replace(re4, 'u') | |
| .replace(re5, 'i') | |
| .replace('ç', 'c') | |
| .replace('Ç', 'c'); | |
| return s; | |
| } | |
| /** | |
| * Recebe resposta do Solr e parseia os resultados. | |
| * | |
| * @param chunk Array Dados do solr | |
| * @param currentItem Object item atual de musicList | |
| * @param [probablyList=false] Boolean Retornar prováveis resultados. | |
| */ | |
| function matchSolrResults(res, currentItem, probablyList) { | |
| if (res.numFound > 0) { | |
| var found = null, | |
| query = currentItem.q, | |
| f = new Fuse(res.docs, { | |
| keys: ['full_txt'], | |
| caseSensitive: false, | |
| //threshold: 0.2 | |
| }), | |
| search = f.search(query); | |
| // Se o bitap retornar uma única ocorrência, é ela | |
| if (search.length === 1) { | |
| found = search[0]; | |
| } else { | |
| var query_ascii = txt_tirar_acentos(query.toLowerCase()); | |
| // Se o bitap retornar mais de uma ocorrência, | |
| // decidimos a melhor opção, caso haja | |
| search.forEach(function(result) { | |
| // Se não encontrar a ocorrência de artista e música, | |
| // abandona o for | |
| if ( | |
| // Tenta achar o artista | |
| (query_ascii.lastIndexOf( | |
| txt_tirar_acentos(result.art.toLowerCase()) | |
| ) === -1) || | |
| // Tenta achar a música | |
| (query_ascii.lastIndexOf( | |
| txt_tirar_acentos(result.txt.toLowerCase()) | |
| ) === -1)) { | |
| return false; | |
| } | |
| var words = txt_tirar_acentos(result.full_txt.toLowerCase()).split(' '), | |
| totWords = words.length, | |
| appearings = 0, | |
| i; | |
| for (i = 0; i < totWords; i++) { | |
| if (query_ascii.indexOf(words[i]) !== -1) { | |
| appearings++; | |
| } | |
| // Se o resultado do bitap, aparece em 80% ou mais | |
| // da query_ascii, assumimos a melhor opção | |
| if ((appearings / totWords) >= 0.8) { | |
| found = result; | |
| return false; | |
| } | |
| } | |
| }); | |
| } | |
| // se não encontrou e deve-se retornar a lista das músicas prováveis | |
| if (found === null) { | |
| if (probablyList === true) { | |
| matches = search.map(function(el) { | |
| el.d = el.dns; | |
| el.u = el.url; | |
| return el; | |
| }); | |
| done(); | |
| } | |
| } else { | |
| // Id da música | |
| currentItem.i = found.imu; | |
| // Dns do artista | |
| currentItem.d = found.dns; | |
| // Id do artista | |
| currentItem.iar = found.iar; | |
| // Gêneros da música | |
| currentItem.g = found.g ? found.g.split(',') : ['unknown']; | |
| // Hits da música | |
| if (true === isNaN(currentItem.h)) { | |
| currentItem.h = found.h; | |
| } | |
| //Url da música | |
| currentItem.u = found.url; | |
| } | |
| } | |
| return currentItem; | |
| } | |
| function solrQuery(pathSearch, currentItem, singleQuery) { | |
| http.get({ | |
| host: SOLR_HOST, | |
| port: SOLR_PORT, | |
| path: pathSearch | |
| }, function(resp) { | |
| resp.on('data', function(chunk) { | |
| if (resp.statusCode === 200) { | |
| matches.push(matchSolrResults(JSON.parse(chunk).response, currentItem, singleQuery)); | |
| } else { | |
| matches.push(currentItem); | |
| } | |
| done(); | |
| }); | |
| }).on('error', function(e) { | |
| done(e.message); | |
| }); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment