X-Git-Url: https://git.rmz.io/dotfiles.git/blobdiff_plain/3beaf9036986d749752eb658a7c83a1c69d04dd4..f737a40a8269639bb3364df31c4d9888e9f12d98:/awesome/widgets/awesompd/jamendo.lua?ds=inline diff --git a/awesome/widgets/awesompd/jamendo.lua b/awesome/widgets/awesompd/jamendo.lua deleted file mode 100644 index 3851e0a..0000000 --- a/awesome/widgets/awesompd/jamendo.lua +++ /dev/null @@ -1,518 +0,0 @@ ---------------------------------------------------------------------------- --- @author Alexander Yakushev --- @copyright 2011-2013 Alexander Yakushev --- @release v1.2.4 ---------------------------------------------------------------------------- - --- Grab environment -local awful = require('awful') - -local jamendo = {} - --- UTILITY STUFF --- Checks whether file specified by filename exists. -local function file_exists(filename, mode) - mode = mode or 'r' - f = io.open(filename, mode) - if f then - f:close() - return true - else - return false - end -end - -local function str_interpose(coll, sep) - if #coll == 0 then - return "" - end - local result = coll[1] - for i = 2, #coll do - result = result .. sep .. coll[i] - end - print(result) - return result -end - --- Global variables -jamendo.FORMAT_MP3 = { display = "MP3 (128k)", - short_display = "MP3", - value = "mp31" } -jamendo.FORMAT_OGG = { display = "Ogg Vorbis (q4)", - short_display = "Ogg", - value = "ogg2" } -jamendo.ORDER_RATINGDAILY = { display = "Daily rating", - short_display = "daily rating", - value = "ratingday_desc" } -jamendo.ORDER_RATINGWEEKLY = { display = "Weekly rating", - short_display = "weekly rating", - value = "ratingweek_desc" } -jamendo.ORDER_RATINGTOTAL = { display = "All time rating", - short_display = "all time rating", - value = "ratingtotal_desc" } -jamendo.ORDER_RANDOM = { display = "Random", - short_display = "random", - value = "random_desc" } -jamendo.ORDER_RELEVANCE = { display = "None (consecutive)", - short_display = "none", - value = "searchweight_desc" } -jamendo.SEARCH_ARTIST = { display = "Artist", - unit = "artist", - value = "artist_id" } -jamendo.SEARCH_ALBUM = { display = "Album", - unit = "album", - value = "album_id" } -jamendo.SEARCH_TAG = { display = "Tag", - unit = "tag", - value = "tag_id" } -jamendo.ALL_FORMATS = { jamendo.FORMAT_MP3, jamendo.FORMAT_OGG } -jamendo.ALL_ORDERS = { ORDER_RELEVANCE, ORDER_RANDOM, ORDER_RATINGDAILY, - ORDER_RATINGWEEKLY, ORDER_RATINGTOTAL } - -jamendo.current_request_table = { unit = "track", - fields = {"id", "artist_url", "artist_name", "name", - "stream", "album_image", "album_name" }, - joins = { "track_album", "album_artist" }, - params = { streamencoding = jamendo.FORMAT_MP3, - order = jamendo.ORDER_RATINGWEEKLY, - n = 100 }} - --- Local variables -local jamendo_list = {} -local cache_file = awful.util.getdir ("cache").."/jamendo_cache" -local cache_header = "[version=1.1.0]" -local album_covers_folder = awful.util.getdir("cache") .. "/jamendo_covers/" -local default_mp3_stream = nil -local search_template = { fields = { "id", "name" }, - joins = {}, - params = { order = ORDER_RELEVANCE, - n = 1}} - --- DEPRECATED. Will be removed in the next major release. --- Returns default stream number for MP3 format. Requests API for it --- not more often than every hour. -local function get_default_mp3_stream() - if not default_mp3_stream or - (os.time() - default_mp3_stream.last_checked) > 3600 then - local trygetlink = - jamendo.perform_request("echo $(curl -w %{redirect_url} " .. - "'http://api.jamendo.com/get2/stream/track/redirect/" .. - "?streamencoding="..jamendo.FORMAT_MP3.value.."&id=729304')") - local _, _, prefix = string.find(trygetlink, "stream(%d+)%.jamendo%.com") - default_mp3_stream = { id = prefix, last_checked = os.time() } - end - return default_mp3_stream.id -end - --- Returns the track ID from the given link to Jamendo stream. If the --- given text is not the Jamendo stream returns nil. -function jamendo.get_id_from_link(link) - local _, _, id = string.find(link,"storage%-new.newjamendo.com/%?trackid=(%d+)") - return id -end - --- Returns link to music stream for the given track ID. Uses MP3 --- format and the default stream for it. -local function get_link_by_id(id) - -- This function is subject to change in the future. - return string.format("http://storage-new.newjamendo.com?trackid=%s&format=mp31&u=0", id) -end - --- -- Returns the album id for given music stream. --- function get_album_id_by_link(link) --- local id = get_id_from_link(link, true) --- if id and jamendo_list[id] then --- return jamendo_list[id].album_id --- end --- end - --- Returns the track table for the given music stream. -function jamendo.get_track_by_link(link) - local id = jamendo.get_id_from_link(link, true) - if id and jamendo_list[id] then - return jamendo_list[id] - end -end - --- If a track is actually a Jamendo stream, replace it with normal --- track name. -function jamendo.replace_link(track_name) - local track = jamendo.get_track_by_link(track_name) - if track then - return track.display_name - else - return track_name - end -end - --- Returns table of track IDs, names and other things based on the --- request table. -function jamendo.return_track_table(request_table) - local req_string = jamendo.form_request(request_table) - local response = jamendo.perform_request(req_string) - if not response then - return nil -- Bad internet connection - end - local parse_table = jamendo.parse_json(response) - for i = 1, #parse_table do - if parse_table[i].stream == "" then - -- Some songs don't have Ogg stream, use MP3 instead - parse_table[i].stream = get_link_by_id(parse_table[i].id) - end - _, _, parse_table[i].artist_link_name = - string.find(parse_table[i].artist_url, "\\/artist\\/(.+)") - -- Remove Jamendo escape slashes - parse_table[i].artist_name = - string.gsub(parse_table[i].artist_name, "\\/", "/") - parse_table[i].name = string.gsub(parse_table[i].name, "\\/", "/") - - parse_table[i].display_name = - parse_table[i].artist_name .. " - " .. parse_table[i].name - -- Do Jamendo a favor, extract album_id for the track yourself - -- from album_image link :) - local _, _, album_id = - string.find(parse_table[i].album_image, "\\/(%d+)\\/covers") - parse_table[i].album_id = album_id or 0 - -- Save fetched tracks for further caching - jamendo_list[parse_table[i].id] = parse_table[i] - end - jamendo.save_cache() - return parse_table -end - --- Generates the request to Jamendo API based on provided request --- table. If request_table is nil, uses current_request_table instead. --- For all values that do not exist in request_table use ones from --- current_request_table. --- return - HTTP-request -function jamendo.form_request(request_table) - local curl_str = "curl -A 'Mozilla/4.0' -fsm 5 \"%s\"" - local url = "http://api.jamendo.com/get2/%s/%s/json/%s/?%s" - request_table = request_table or jamendo.current_request_table - - local fields = request_table.fields or jamendo.current_request_table.fields - local joins = request_table.joins or jamendo.current_request_table.joins - local unit = request_table.unit or jamendo.current_request_table.unit - - -- Form fields string (like field1+field2+fieldN) - local f_string = str_interpose(fields, "+") - -- Form joins string - local j_string = str_interpose(joins, "+") - - local params = {} - -- If parameters where supplied in request_table, add them to the - -- parameters in current_request_table. - if request_table.params and - request_table.params ~= jamendo.current_request_table.params then - -- First fill params with current_request_table parameters - for k, v in pairs(jamendo.current_request_table.params) do - params[k] = v - end - -- Then add and overwrite them with request_table parameters - for k, v in pairs(request_table.params) do - params[k] = v - end - else -- Or just use current_request_table.params - params = jamendo.current_request_table.params - end - -- Form parameter string (like param1=value1¶m2=value2) - local param_string = "" - for k, v in pairs(params) do - if type(v) == "table" then - v = v.value - end - v = string.gsub(v, " ", "+") - param_string = param_string .. "&" .. k .. "=" .. v - end - - return string.format(curl_str, string.format(url, f_string, unit, j_string, param_string)) -end - --- Primitive function for parsing Jamendo API JSON response. Does not --- support arrays. Supports only strings and numbers as values. --- Provides basic safety (correctly handles special symbols like comma --- and curly brackets inside strings) --- text - JSON text -function jamendo.parse_json(text) - local parse_table = {} - local block = {} - local i = 0 - local inblock = false - local instring = false - local curr_key = nil - local curr_val = nil - while i and i < string.len(text) do - if not inblock then -- We are not inside the block, find next { - i = string.find(text, "{", i+1) - inblock = true - block = {} - else - if not curr_key then -- We haven't found key yet - if not instring then -- We are not in string, check for more tags - local j = string.find(text, '"', i+1) - local k = string.find(text, '}', i+1) - if j and j < k then -- There are more tags in this block - i = j - instring = true - else -- Block is over, we found its ending - i = k - inblock = false - table.insert(parse_table, block) - end - else -- We are in string, find its ending - _, i, curr_key = string.find(text,'(.-[^%\\])"', i+1) - instring = false - end - else -- We have the key, let's find the value - if not curr_val then -- Value is not found yet - if not instring then -- Not in string, check if value is string - local j = string.find(text, '"', i+1) - local k = string.find(text, '[,}]', i+1) - if j and j < k then -- Value is string - i = j - instring = true - else -- Value is int - _, i, curr_val = string.find(text,'(%d+)', i+1) - end - else -- We are in string, find its ending - local j = string.find(text, '"', i+1) - if j == i+1 then -- String is empty - i = j - curr_val = "" - else - _, i, curr_val = string.find(text,'(.-[^%\\])"', i+1) - curr_val = jamendo.utf8_codes_to_symbols(curr_val) - end - instring = false - end - else -- We have both key and value, add it to table - block[curr_key] = curr_val - curr_key = nil - curr_val = nil - end - end - end - end - return parse_table -end - --- Jamendo returns Unicode symbols as \uXXXX. Lua does not transform --- them into symbols so we need to do it ourselves. -function jamendo.utf8_codes_to_symbols (s) - local hexnums = "[%dabcdefABCDEF]" - local pattern = string.format("\\u(%s%s%s%s?)", - hexnums, hexnums, hexnums, hexnums) - local decode = function(code) - code = tonumber(code, 16) - if code < 128 then -- one-byte symbol - return string.char(code) - elseif code < 2048 then -- two-byte symbol - -- Grab high and low bytes - local hi = math.floor(code / 64) - local lo = math.fmod(code, 64) - -- Return symbol as \hi\lo - return string.char(hi + 192, lo + 128) - elseif code < 65536 then - -- Grab high, middle and low bytes - local hi = math.floor(code / 4096) - local leftover = code - hi * 4096 - local mi = math.floor(leftover / 64) - leftover = leftover - mi * 64 - local lo = math.fmod(leftover, 64) - -- Return symbol as \hi\mi\lo - return string.char(hi + 224, mi + 160, lo + 128) - elseif code < 1114112 then - -- Grab high, highmiddle, lowmiddle and low bytes - local hi = math.floor(code / 262144) - local leftover = code - hi * 262144 - local hm = math.floor(leftover / 4096) - leftover = leftover - hm * 4096 - local lm = math.floor(leftover / 64) - local lo = math.fmod(leftover, 64) - -- Return symbol as \hi\hm\lm\lo - return string.char(hi + 240, hm + 128, lm + 128, lo + 128) - else -- It is not Unicode symbol at all - return tostring(code) - end - end - return string.gsub(s, pattern, decode) -end - --- Retrieves mapping of track IDs to track names and album IDs to --- avoid redundant queries when Awesome gets restarted. -local function retrieve_cache() - local bus = io.open(cache_file) - local track = {} - if bus then - local header = bus:read("*line") - if header == cache_header then - for l in bus:lines() do - local _, _, id, artist_link_name, album_name, album_id, track_name = - string.find(l,"(%d+)-([^-]+)-([^-]+)-(%d+)-(.+)") - track = {} - track.id = id - track.artist_link_name = string.gsub(artist_link_name, '\\_', '-') - track.album_name = string.gsub(album_name, '\\_', '-') - track.album_id = album_id - track.display_name = track_name - jamendo_list[id] = track - end - else - -- We encountered an outdated version of the cache - -- file. Let's just remove it. - awful.util.spawn("rm -f " .. cache_file) - end - end -end - --- Saves track IDs to track names and album IDs mapping into the cache --- file. -function jamendo.save_cache() - local bus = io.open(cache_file, "w") - bus:write(cache_header .. "\n") - for id,track in pairs(jamendo_list) do - bus:write(string.format("%s-%s-%s-%s-%s\n", id, - string.gsub(track.artist_link_name, '-', '\\_'), - string.gsub(track.album_name, '-', '\\_'), - track.album_id, track.display_name)) - end - bus:flush() - bus:close() -end - --- Retrieve cache on initialization -retrieve_cache() - --- Returns a filename of the album cover and formed wget request that --- downloads the album cover for the given track name. If the album --- cover already exists returns nil as the second argument. -function jamendo.fetch_album_cover_request(track_id) - local track = jamendo_list[track_id] - local album_id = track.album_id - - if album_id == 0 then -- No cover for tracks without album! - return nil - end - local file_path = album_covers_folder .. album_id .. ".jpg" - - if not file_exists(file_path) then -- We need to download it - -- First check if cache directory exists - f = io.popen('test -d ' .. album_covers_folder .. ' && echo t') - if f:read("*line") ~= 't' then - awful.util.spawn("mkdir " .. album_covers_folder) - end - f:close() - - if not track.album_image then -- Wow! We have album_id, but - local a_id = tostring(album_id) --don't have album_image. Well, - local prefix = --it happens. - string.sub(a_id, 1, #a_id - 3) - track.album_image = - string.format("http://imgjam.com/albums/s%s/%s/covers/1.100.jpg", - prefix == "" and 0 or prefix, a_id) - end - - return file_path, string.format("wget %s -O %s 2> /dev/null", - track.album_image, file_path) - else -- Cover already downloaded, return its filename and nil - return file_path, nil - end -end - --- Returns a file containing an album cover for given track id. First --- searches in the cache folder. If file is not there, fetches it from --- the Internet and saves into the cache folder. -function jamendo.get_album_cover(track_id) - local file_path, fetch_req = jamendo.fetch_album_cover_request(track_id) - if fetch_req then - local f = io.popen(fetch_req) - f:close() - - -- Let's check if file is finally there, just in case - if not file_exists(file_path) then - return nil - end - end - return file_path -end - --- Same as get_album_cover, but downloads (if necessary) the cover --- asynchronously. -function jamendo.get_album_cover_async(track_id) - local file_path, fetch_req = jamendo.fetch_album_cover_request(track_id) - if fetch_req then - asyncshell.request(fetch_req) - end -end - --- Checks if track_name is actually a link to Jamendo stream. If true --- returns the file with album cover for the track. -function jamendo.try_get_cover(track_name) - local id = jamendo.get_id_from_link(track_name) - if id then - return jamendo.get_album_cover(id) - end -end - --- Same as try_get_cover, but calls get_album_cover_async inside. -function jamendo.try_get_cover_async(track_name) - local id = jamendo.get_id_from_link(track_name) - if id then - return jamendo.get_album_cover_async(id) - end -end - --- Returns the track table for given query and search method. --- what - search method - SEARCH_ARTIST, ALBUM or TAG --- s - string to search -function jamendo.search_by(what, s) - -- Get a default request and set unit and query - local req = search_template - req.unit = what.unit - req.params.searchquery = s - local resp = jamendo.perform_request(jamendo.form_request(req)) - if resp then - local search_res = jamendo.parse_json(resp)[1] - - if search_res then - -- Now when we got the search result, find tracks filtered by - -- this result. - local params = {} - params[what.value] = search_res.id - req = { params = params } - local track_table = jamendo.return_track_table(req) - return { search_res = search_res, tracks = track_table } - end - end -end - --- Executes request_string with io.popen and returns the response. -function jamendo.perform_request(request_string) - local bus = assert(io.popen(request_string,'r')) - local response = bus:read("*all") - bus:close() - -- Curl with popen can sometimes fail to fetch data when the - -- connection is slow. Let's try again if it fails. - if #response == 0 then - bus = assert(io.popen(request_string,'r')) - response = bus:read("*all") - bus:close() - -- If it still can't read anything, return nil - if #response ~= 0 then - return nil - end - end - return response -end - --- Sets default streamencoding in current_request_table. -function jamendo.set_current_format(format) - jamendo.current_request_table.params.streamencoding = format -end - --- Sets default order in current_request_table. -function jamendo.set_current_order(order) - jamendo.current_request_table.params.order = order -end - -return jamendo