Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial commit (import from old songlocator repo)
- Loading branch information
0 parents
commit 8e1282d
Showing
7 changed files
with
549 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
SRC = $(shell find . -name '*.coffee' -type f) | ||
LIB = $(SRC:%.coffee=%.js) | ||
|
||
all: $(LIB) | ||
|
||
clean: | ||
rm -f $(LIB) | ||
|
||
publish: | ||
git push | ||
git push --tags | ||
npm publish | ||
|
||
%.js: %.coffee | ||
coffee --map -bc $< |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
SongLocator resovler for YouTube |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"name": "songlocator-youtube", | ||
"version": "0.1.0", | ||
"description": "SongLocator resolver for YouTube", | ||
"tags": ["songlocator", "api", "music", "streaming", "audio", "resolver", "youtube"], | ||
"author": "Andrey Popp <8mayday@gmail.com>", | ||
"main": ["./songlocator-youtube.js"], | ||
"dependencies": { | ||
"songlocator-base": "~0.1.1" | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"name": "songlocator-youtube", | ||
"version": "0.1.0", | ||
"description": "SongLocator resovler for YouTube", | ||
"main": "songlocator-youtube.js", | ||
"dependencies": { | ||
"songlocator-base": "~0.1.1" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/songlocator/songlocator-youtube.git" | ||
}, | ||
"homepage": "https://github.com/songlocator/songlocator-youtube", | ||
"keywords": ["songlocator", "api", "music", "streaming", "audio", "resolver", "youtube"], | ||
"author": { | ||
"name": "Andrey Popp", | ||
"email": "8mayday@gmail.com", | ||
"url": "http://andreypopp.com" | ||
}, | ||
"license": "MIT" | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
### | ||
SongLocator resolver for YouTube. | ||
2013 (c) Andrey Popp <8mayday@gmail.com> | ||
Based on Tomahawk YouTube resolver. | ||
2012 (C) Hugo Lindström <hugolm84@gmail.com> | ||
2012 (C) Thierry Göckel <thierry@strayrayday.lu> | ||
2012 (C) Leo Franchi <lfranchi@kde.org> | ||
This program is free software: you can redistribute it and/or modify | ||
it under the terms of the GNU Affero General Public License as published by | ||
the Free Software Foundation, either version 3 of the License, or | ||
(at your option) any later version. | ||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU Affero General Public License for more details. | ||
You should have received a copy of the GNU Affero General Public License | ||
along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
### | ||
|
||
((root, factory) -> | ||
if typeof exports == 'object' | ||
SongLocator = require('songlocator-base') | ||
module.exports = factory(SongLocator) | ||
else if typeof define == 'function' and define.amd | ||
define (require) -> | ||
SongLocator = require('songlocator-base') | ||
root.SongLocator.YouTube = factory(SongLocator) | ||
else | ||
root.SongLocator.YouTube = factory(SongLocator) | ||
|
||
) this, ({BaseResolver, extend}) -> | ||
|
||
regexIndexOf = (s, regex, startpos) -> | ||
indexOf = s.substring(startpos || 0).search(regex) | ||
return if indexOf >= 0 then indexOf + (startpos || 0) else indexOf | ||
|
||
class Resolver extends BaseResolver | ||
name: 'youtube' | ||
|
||
search: (qid, query) -> | ||
url = 'http://gdata.youtube.com/feeds/api/videos/' | ||
params = {alt: 'jsonc', q: query, 'max-results': this.options.searchMaxResults, v: 2} | ||
this.request | ||
url: url | ||
params: params | ||
callback: (error, response) => | ||
return if error | ||
return if response.data.totalItems == 0 | ||
results = for item in response.data.items | ||
result = this.item2result(item, query) | ||
continue unless result? | ||
result | ||
this.results(qid, results) | ||
|
||
resolve: (qid, title, artist, album) -> | ||
query = [artist or '', title or ''].join(' ').trim() | ||
this.search(qid, query) | ||
|
||
item2result: (item, query) -> | ||
return unless item.title and item.duration and not item.contentRating | ||
return unless this.dirtyCheckTitle(item.title, query) | ||
|
||
parsedTrack = this.cleanupAndParseTrack(item.title, query) | ||
|
||
return if not parsedTrack or not parsedTrack.artist? | ||
|
||
return unless this.getTrack(item.title, query, true) | ||
|
||
{ | ||
title: parsedTrack.track | ||
artist: parsedTrack.artist | ||
album: undefined | ||
|
||
source: this.name | ||
id: item.id | ||
|
||
linkURL: item.player['default'] + '&hd=1' | ||
imageURL: item.thumbnail?.hqDefault or item.thumbnail?.sqDefault | ||
audioURL: undefined # we cannot know the direct link to the audio stream | ||
audioPreviewURL: undefined | ||
|
||
mimetype: "video/h264" | ||
duration: item.duration | ||
} | ||
|
||
dirtyCheckTitle: (title, query) -> | ||
# dirty check, filters out the most of the unwanted results | ||
titleItem = title | ||
.replace(/([^A-Za-z0-9\s])/gi, "") | ||
.replace(/(?:(?:^|\n)\s+|\s+(?:$|\n))/g,'') | ||
.replace(/\s+/g,'|'); | ||
queryItem = query | ||
.replace(/([^A-Za-z0-9\s])/gi, "") | ||
.replace(/(?:(?:^|\n)\s+|\s+(?:$|\n))/g,'') | ||
.replace(/\s+/g,'|'); | ||
matches = titleItem.match(RegExp(queryItem, 'gi')) | ||
|
||
matches and matches.length == queryItem.split("|").length | ||
|
||
cleanupAndParseTrack: (title, query) -> | ||
result = {} | ||
|
||
# For the ease of parsing, remove these | ||
# Maybe we could up the score a bit? | ||
if regexIndexOf(title, /(?:[([](?=(official))).*?(?:[)\]])|(?:(official|video)).*?(?:(video))/i, 0 ) != -1 | ||
title = title.replace(/(?:[([](?=(official|video))).*?(?:[)\]])/gi, "") | ||
title = title.replace(/(official|video(?:([!:-])))/gi, "") | ||
result.isOfficial = 1 | ||
|
||
result.query = title | ||
|
||
# Sometimes users separate titles with quotes : | ||
# eg, "\"Young Forever\" Jay Z | Mr. Hudson (OFFICIAL VIDEO)" | ||
# this will parse out the that title | ||
inQuote = title.match(/([""'])(?:(?=(\\?))\2.).*\1/g); | ||
|
||
if inQuote and inQuote != undefined | ||
result.track = inQuote[0].substr(1, inQuote[0].length-2) | ||
title = title.replace(inQuote[0],'') | ||
result.fromQuote = result.track | ||
|
||
result.parsed = this.parseCleanTrack( title ) | ||
|
||
if result.parsed | ||
result.parsed.track = result.track | ||
return result.parsed | ||
|
||
else | ||
result.parsed = this.parseCleanTrack(title) | ||
if result.parsed | ||
return result.parsed | ||
|
||
# Still no luck, lets go deeper | ||
if !result.parsed | ||
if title.toLowerCase().indexOf(query.toLowerCase()) != -1 | ||
result.parsed = this.parseCleanTrack(title.replace(RegExp(query, "gi"), query.concat(" :"))) | ||
else | ||
tryMatch = query.replace(/(?:[-|:&])/g, " ") | ||
if title.toLowerCase().indexOf(tryMatch.toLowerCase()) != -1 | ||
replaceWith = if regexIndexOf(title, /(?:[-|:&])/g, 0) != -1 | ||
query | ||
else | ||
query.concat(" : ") | ||
result.parsed = this.parseCleanTrack( title.replace(RegExp(tryMatch, "gi"), replaceWith)) | ||
|
||
if result.fromQuote and result.fromQuote != undefined | ||
if result.parsed | ||
result.artist = result.parsed.artist | ||
result.track = result.fromQuote | ||
|
||
else if result.parsed | ||
if result.parsed.artist != undefined | ||
result.artist = result.parsed.artist | ||
if result.parsed.track != undefined | ||
result.track = result.parsed.track | ||
|
||
delete result.parsed | ||
result | ||
|
||
parseCleanTrack: (track) -> | ||
result = {} | ||
result.query = track | ||
result.query.replace /.*?(?=([-:|]\s))/g, (param) -> | ||
if param != "" | ||
if result.artist == undefined | ||
result.artist = param | ||
else | ||
if result.track == undefined | ||
result.track = param | ||
|
||
result.query.replace /(?=([-:|]\s)).*/g, (param) -> | ||
if param != "" | ||
if regexIndexOf(param, /([-|:]\s)/g, 0) == 0 | ||
if result.track == undefined | ||
result.track = param.replace(/([-|:]\s)/g, "") | ||
else | ||
if tyresult.artist == undefined | ||
result.artist = param | ||
result.track = result.replace(/([-|:]\s)/g, "") | ||
|
||
if result.track != undefined and result.artist != undefined | ||
# Now, lets move featuring to track title, where it belongs | ||
ftmatch = result.artist.match(/(?:(\s)(?=(feat.|feat|ft.|ft|featuring)(?=(\s)))).*/gi) | ||
if ftmatch | ||
result.artist = result.artist.replace(ftmatch, "") | ||
result.track += " " + ftmatch | ||
|
||
# Trim | ||
result.track = result.track.replace(/(?:(?:^|\n)\s+|\s+(?:$|\n))/g,'').replace(/\s+/g,' ') | ||
result.artist = result.artist.replace(/(?:(?:^|\n)\s+|\s+(?:$|\n))/g,'').replace(/\s+/g,' ') | ||
return result | ||
|
||
return | ||
|
||
getTrack: (trackTitle, origTitle, isSearch) -> | ||
if (this.options.includeCovers == false or this.options.includeCovers == undefined) \ | ||
and trackTitle.search(/(\Wcover(?!(\w)))/i) != -1 \ | ||
and origTitle.search(/(\Wcover(?!(\w)))/i) == -1 | ||
return | ||
|
||
# Allow remix:es in search results? | ||
if isSearch == undefined | ||
if (this.options.includeRemixes == false or this.options.includeRemixes == undefined) \ | ||
and trackTitle.search(/(\W(re)*?mix(?!(\w)))/i) != -1 \ | ||
and origTitle.search(/(\W(re)*?mix(?!(\w)))/i) == -1 | ||
return | ||
|
||
if (this.options.includeLive == false or this.options.includeLive == undefined) \ | ||
and trackTitle.search(/(live(?!(\w)))/i) != -1 \ | ||
and origTitle.search(/(live(?!(\w)))/i) == -1 | ||
return | ||
|
||
else | ||
return trackTitle | ||
|
||
{Resolver} |
Oops, something went wrong.