SoundCloud Leecher v0.5
By Elektro H@cker
(http://img268.imageshack.us/img268/7560/soundcloudd.png)
(http://img708.imageshack.us/img708/189/captura2vx.png)
(http://img843.imageshack.us/img843/3328/captura2tr.png.png)
(http://img197.imageshack.us/img197/9848/captura1d.png)
(http://img692.imageshack.us/img692/3369/captura2j.png)
(http://img33.imageshack.us/img33/9832/captura3o.png)
(http://img43.imageshack.us/img43/9933/captura4p.png)
(http://img546.imageshack.us/img546/7489/verbosemode.png)
SoundCloud Leecher es una herramienta que te ayudará a mantener al día tu colección de música.
Esta utilidad está pensada para un uso (casi) diario o semanal.
El script obtiene todos los enlaces descargables de las primeras "X" páginas de "X" grupo de Soundcloud, y guarda esos enlaces en un archivo de texto para usarlos más tarde con un gestor de descargas como por ejemplo "JDownloader".
Además, todos los enlaces se listan también en un archivo log para que queden excluidos en el próximo uso del script, esa es la razón de porqué está pensado para el uso diario.
Es muy fácil de configurar.
Espero que a alguien más que a mi le sirva de ayuda. ::)
Un saludo!
Executable: http://exoshare.com/download.php?uid=OFGDPH4C
Soundcloud Leecher.rb:
# -*- coding: UTF-8 -*-
# SoundCloud Leecher v0.5
#
# By Elektro H@cker
# Description:
# -----------
#
# SoundCloud Leecher it's a tool that helps you to keep updated your music collection.
#
# This tool is intended for (almost) daily use.
#
# The script retreives all the downloadable links of the first "X" pages from a "X" group of SoundCloud,
# And then list the links into a text file for use it with a download magaer like "JDownloader".
#
# All the links are stored permanently into a log file to be excluded at the next use,
# that's the reason why this tool is intended for daily use.
# Info:
# ----
#
# SoundCloud unfortunately do not have a date search mode,
# which would be much easier to search/sort by "music style + today's date" than "groups + first sorted pages",
# The site has an advanced search engine that can search by "release date" but that is not the same than "uploaded date",
# So i think the only way to sort by date is by entering a group page because it shows the content sorted by the last date.
# How to use:
# ----------
#
# Configure your favorite groups and the other settings by entering into the configuration menu.
require 'net/http'
require 'win32/registry'
require "highline/system_extensions"
include HighLine::SystemExtensions
exit if Object.const_defined?(:Ocra)
def logo()
	puts "
  _,  _, ,  , ,  , ,_   _ ,    _, ,  , ,_      ,    _, _, _ , ,  _,,_   
 (_  / \\ |  | |\\ | | \\ /  |   / \\ |  | | \\     |   /_,/_,/  |_| /_,|_)  
  _) \\_/ \\__| | \\| |_/ \\_ |__ \\_/ \\__| |_/     |__ \\_ \\_ \\_ | | \\_ | \\  
 '          `    `       `           `           '   `  `  `' `   `'   
                                                                  v0.5
 By Elektro H@cker"
end
def main()
	puts "\n\n[+] Press \"C\" to config or press any other key to start leeching..."
	key = get_character
	config("") if key.to_s =~ /^67$|^99$/
	get_downloads_list()
	puts "\n\n\n[+] All links are stored in: #{$leecherfile}"
end
def get_settings()
	begin
		$logfile = regread("LOGFILEPATH")
	rescue
		$logfile = "#{ENV['WINDIR']}\\Soundcloud LOG.txt"
	end
	begin
		$leecherfile = regread("LEECHERFILEPATH") +  "Soundcloud Leecher #{Time.new.strftime("%Y-%m-%d")}.txt"
	rescue
		$leecherfile = "#{ENV['USERPROFILE']}\\Desktop\\Soundcloud Leecher #{Time.new.strftime("%Y-%m-%d")}.txt"
	end
	begin
		$groups = regread("GROUPS")
	rescue
		$groups = ""
	end
	begin
		$max_pages = regread("MAXPAGES")
		$max_pages = $max_pages.to_i
	rescue
		$max_pages = 5
	end
	begin
		$min_duration = regread("MINDURATION")+"00"
		$min_duration = $min_duration.to_i
	rescue
		$min_duration = 130
	end
	begin
		$max_duration = regread("MAXDURATION")+"00"
		$max_duration = $max_duration.to_i
	rescue
		$max_duration = 1200
	end
	begin
		$max_size = regread("MAXSIZE")+"00"
		$max_size = $max_size.to_i
	rescue
		$max_size = 10000
	end
	begin
		$excluded_exts = regread("EXCLUDED EXTENSIONS")
	rescue
		$excluded_exts = ""
	end
	begin
		$excluded_tags = regread("EXCLUDED TAGNAMES")
	rescue
		$excluded_tags = ""
	end
	begin
		$verbose = regread("VERBOSEMODE")
	rescue
		$verbose = "no"
	end
end
def config(errorcode)
	puts "
º---------------------------------º---------------------------------º
| [1] Set the log file path       | [+] Max. track duration         |
| [2] Set the leecher file path   | [-] Min. track duration         |
| [3] Delete the log file         | [M] Max. track filesize         |
|---------------------------------|---------------------------------|
| [A] Add a group name            | [P] Pages per group to parse    |
| [D] Delete a group name         | [F] Filetypes to exclude        |
| [L] List the group names        | [T] Tagnames to exclude         |
|---------------------------------|---------------------------------|
| [V] Verbose mode (ON/OFF)       | [S] Show the current settings   |
|---------------------------------| [R] Reset the settings          |
| [E] Exit                        | [Z] Backup all the config.      |
º---------------------------------º---------------------------------º
"
	get_settings()
	puts errorcode
	keystr = "NOTHING"
	until keystr =~ /^43$|^45$|^49$|^50$|^51$|^65$|^68$|^69$|^70$|^76$|^77$|^80$|^82$|^83$|^84$|^86$|^90$|^97$|^100$|^101$|^102$|^108$|^109$|^112$|^114$|^115$|^116$|^118$|^121$|^122$/
		print "\nChoose an option >> "
		key = get_character
		keystr = key.to_s
	end
	# Log file path
	if key == 49
		logfilepath = "NOTHING"
		until File.directory?(logfilepath)
			print "\n\nEnter the path to an existing directory for the logfile: "
			logfilepath = STDIN.gets.chomp
		end
		if logfilepath[-1] == '\\' then logfilepath = logfilepath[0..-2] end
		regwrite("LOGFILEPATH", logfilepath + "\\Soundcloud LOG.txt")
		config("[+] Operation completed.")
	end
	# Leecher file path
	if key == 50
		leecherfile = "NOTHING"
		until File.directory?(leecherfile)
			print "\n\Enter the path to an existing directory for the leecher file: "
			leecherfile = STDIN.gets.chomp
		end
		if not leecherfile[-1] == '\\' then leecherfile = leecherfile+"\\" end
		regwrite("LEECHERFILEPATH", leecherfile)
		config("[+] Operation completed.")
	end
	# delete log file
	if key == 51
		filedel = "NOTHING"
		while not filedel =~ /^78$|^89$|^110$|^121$/
			print "\n\nWant to delete the log file, Are you sure? [Y/N]: "
			filedel = get_character.to_s
		end
		begin
			if filedel =~ /^89$|^121$/ then File.delete($logfile) end
			config("[+] Operation completed.")
		rescue
			config("\n\nERROR\n\nCan't find the logfile.")
		end
	end
	# Add groupname
	if key == 65 or key == 97
		addname = "NOTHING"
		until not addname == "NOTHING"
			print "\n\nEnter a group name to add\nor enter the word \"none\" to reset the group list: "
			addname = STDIN.gets.chomp
		end
		begin
			groups=regread("GROUPS")
		rescue
			groups=""
		end
		for addgroupname in regread("GROUPS").split(";").sort do
 			if not addgroupname =~ /^#{Regexp.escape(addname)}$/i then addfinalgroups="#{addfinalgroups};#{addgroupname}" else found = "yes" end	
		end
		if found == "yes" then config("\n\n[+] ERROR\n\nThe groupname already exists.") end
		if addname =~ /^none$/i then regwrite("GROUPS", "") else regwrite("GROUPS", "#{groups};#{addname}") end
		config("[+] Operation completed.")
	end
	# delete groupname
	if key == 68 or key == 100
		delnum = "NOTHING"
		num=0
		for listname in $groups.split(";").each.sort do
			num=num+1
			puts " [#{num}]	#{listname}"
			instance_variable_set "@_#{num}", listname
		end
		until not delnum == "NOTHING"
			print "\n\nEnter a reference number to delete the group\nor enter the word \"none\" to reset the group list: "
			delnum = STDIN.gets.chomp
		end
		choose = instance_variable_get "@_#{delnum}"
		begin
			groups=regread("GROUPS")
		rescue
			groups=""
		end
		begin
			for delgroupname in regread("GROUPS").split(";").sort do
 				if not delgroupname =~ /^#{Regexp.escape(choose)}$/i then delfinalgroups="#{delfinalgroups};#{delgroupname}" end	
			end
		rescue
			config("\n\n[+] ERROR\n\nCan't find the delgroupname.")
		end	
		regwrite("GROUPS", delfinalgroups[1..-1])
		config("[+] Operation completed.")
	end
	# list groupnames
	if key == 76 or key == 108
		num = 0
		puts "\n\n[+] All your groups:\n\n"
		for listname in $groups.split(";").each.sort do
			num=num+1
			puts " [#{num}]	#{listname}"
		end
		puts "\n\n[+] Press any other key to continue..."
		get_character
	    config("[+] Operation completed.")
	end
	# Max pages
	if key == 80 or key == 112
		maxpages = "NOTHING"
		puts "\n\nThis option lets you configure the maximum pages when leeching a group..."
		until not maxpages[/[a-z]/i]
			print "\nEnter a number for the max pages value: "
			maxpages = STDIN.gets.chomp
		end
		regwrite("MAXPAGES", maxpages)
		config("[+] Operation completed.")
	end
	# Min track duration
	if key == 45
		puts "\n\nThis option lets you configure the minimum accepted minutes duration when leeching tracks..."
		minlenght = "NOTHING"
		until minlenght[/^[0-9]+$/]
			print "\nEnter a number to set the min. minutes for a track (Example: \"1\"): "
			minlenght = STDIN.gets.chomp
		end
		regwrite("MINDURATION", minlenght)
		config("[+] Operation completed.")
	end
	# Max track duration
	if key == 43
		puts "\n\nThis option lets you configure the maximum accepted minutes duration when leeching tracks..."
		maxlenght = "NOTHING"
		until maxlenght[/^[0-9]+$/]
			print "\nEnter a number to set the max. minutes for a track (Example: \"15\"): "
			maxlenght = STDIN.gets.chomp
		end
		regwrite("MAXDURATION", maxlenght)
		config("[+] Operation completed.")
	end
	# Max track filesize
	if key == 77 or key == 109
		puts "\n\nThis option lets you configure the maximum accepted filesize when leeching tracks..."
		maxsize = "NOTHING"
		until maxsize[/^[0-9]+$/]
			print "\nEnter a number to set the max. MB for a track (Example: \"20\"): "
			maxsize = STDIN.gets.chomp
		end
		regwrite("MAXSIZE", maxsize)
		config("[+] Operation completed.")
	end
	# exclude filetypes
	if key == 102 or key == 70
		addext = "NOTHING"
		puts "\n\nThis option lets you exclude tracks by their file extension..."
		until not addext == "NOTHING"
			print "\n\nEnter a file extension (Example: \"wav\") \nor enter the word \"none\" to reset the exclusions: "
			addext = STDIN.gets.chomp
		end
		begin
			exts=regread("EXCLUDED EXTENSIONS")
		rescue
			exts=""
		end
		if addext =~ /^none$/i then regwrite("EXCLUDED EXTENSIONS", "") else regwrite("EXCLUDED EXTENSIONS", "#{exts};#{addext.gsub(".","")}") end
		config("[+] Operation completed.")
	end
	# exclude tagnames
	if key == 84 or key == 116
		addtag = "NOTHING"
		puts "\n\nThis option lets you exclude tracks by a tagname..."
		until not addtag == "NOTHING"
			print "\n(The tagnames are not case sensitive)\n\nEnter a tagname (Example: \"session\") \nor enter the word \"none\" to reset the exclusions: "
			addtag = STDIN.gets.chomp
		end
		begin
			tags=regread("EXCLUDED TAGNAMES")
		rescue
			tags=""
		end
		if addtag =~ /^none$/i then regwrite("EXCLUDED TAGNAMES", "") else regwrite("EXCLUDED TAGNAMES", "#{tags};#{addtag}") end
		config("[+] Operation completed.")
	end
	# verbose mode
	if key == 118 or key == 86
		verbkey = "NOTHING"
		puts "\n\nThe verbose mode lets you can see more info when leeching the group pages..."
		while not verbkey =~ /^78$|^89$|^110$|^121$/
			print "\n\nWant to use the verbose mode? [Y/N]: "
			verbkey = get_character.to_s
		end
		if verbkey =~ /^89$|^121$/ then regwrite("VERBOSEMODE", "yes") else regwrite("VERBOSEMODE", "no") end
		config("[+] Operation completed.")
	end
# show the current settings
 if key == 83 or key == 115
	config("
 Log file path       : #{$logfile}
 Leecher file path   : #{$leecherfile}
 Max. pages per group: #{$max_pages} pages
 Min. track duration : #{$min_duration.to_s[0..-3]} min
 Max. track duration : #{$max_duration.to_s[0..-3]} min
 Max. track filesize : #{$max_size.to_s[0..-3]} mb
 Verbose mode        : #{$verbose}
 Excluded extensions : #{$excluded_exts.gsub(";","|")}
 Excluded tagnames   : #{$excluded_tags.gsub(";","|")}
")
	end
	# reset the settings
	if key == 114 or key == 82
		resetkey = "NOTHING"
		while not resetkey =~ /^78$|^89$|^110$|^121$/
			print "\n(This not affect to group list)\n\nWant to reset all the settings, Are you sure? [Y/N]: "
			resetkey = get_character.to_s
		end
		if resetkey =~ /^89$|^121$/
			Win32::Registry::HKEY_CURRENT_USER.open("SOFTWARE\\Soundcloud Leecher\\", Win32::Registry::KEY_ALL_ACCESS) do |reg|
				reg['LOGFILEPATH'] = 'DELETE'
				reg.delete_value("LOGFILEPATH")
				reg['LEECHERFILEPATH'] = 'DELETE'
				reg.delete_value("LEECHERFILEPATH")
				reg['MAXPAGES'] = 'DELETE'
				reg.delete_value("MAXPAGES")
				reg['MINDURATION'] = 'DELETE'
				reg.delete_value("MINDURATION")
				reg['MAXDURATION'] = 'DELETE'
				reg.delete_value("MAXDURATION")
				reg['MAXSIZE'] = 'DELETE'
				reg.delete_value("MAXSIZE")
				reg['VERBOSEMODE'] = 'DELETE'
				reg.delete_value("VERBOSEMODE")
				reg['EXCLUDED EXTENSIONS'] = 'DELETE'
				reg.delete_value("EXCLUDED EXTENSIONS")
				reg['EXCLUDED TAGNAMES'] = 'DELETE'
				reg.delete_value("EXCLUDED TAGNAMES")
			end
			config("[+] Operation completed.")
		end
	end
	# backup the settings
	if key == 90 or key == 122
		system %[ regedit /e \"%USERPROFILE%\\Desktop\\Soundcloud settings %DATE:/=-%.reg\" \"HKEY_CURRENT_USER\\Software\\Soundcloud Leecher\" ]
		config("\n\n[+] Settings stored in #{ENV['USERPROFILE']}\\Desktop\\SoundCloud settings.reg")
	end
	# exit
	if key == 69 or key == 101 then main() end
		
end
def regread(keyname)
	Win32::Registry::HKEY_CURRENT_USER.open("SOFTWARE\\Soundcloud Leecher\\") do |reg| reg[keyname] end
end
def regwrite(keyname, value)
	Win32::Registry::HKEY_CURRENT_USER.create("SOFTWARE\\Soundcloud Leecher\\") do |reg| reg[keyname, Win32::Registry::REG_SZ] = value end
end
def filewrite()
	if not File.exist?($logfile) then File.open($logfile, "w") do |write| write.puts "SoundCloud leeched URLs\n" end end
	if not File.open($logfile, "r").read[@track_url.split("/download").first.split("http://soundcloud.com/").last.gsub("-","").gsub("/","")]
		if $verbose == "yes" then puts @info end
		File.open($logfile,     "a+") do |write| write.puts @track_url.split("/download").first.split("http://soundcloud.com/").last.gsub("-","").gsub("/","") end
		File.open($leecherfile, "a+") do |write| write.puts "Added at #{Time.new.strftime("%H:%M")}: #{@track_url}" end
	end
end
def get_downloads_list()
	if $verbose == "no"
		for name in $groups.split(";").each.sort do
			@group = name.chomp
			@page  = 0
			print "\n\n[+] Group: #{@group}\n[+] Leeching pages "
			for i in 1..$max_pages do
				@page = @page+1
				@url  = "http://soundcloud.com/groups/#{@group}/tracks?page=#{@page}"
				print "#{@page}/#{$max_pages}..."
				Net::HTTP.get_response(URI.parse(@url)).body.each_line do |line|
					if (line['class="info-header"'])
						@filename = line.split('</a').first.split('>').last.gsub(/ Artwork$/,'').gsub('"','"').gsub('&','&')
						for excluded_tag in $excluded_tags.split(";").each do 
							if not excluded_tag == "" and @filename[/#{Regexp.escape(excluded_tag)}/i] then @downloadable = "no" end
						end
					end	
					if (line['button download']) then @downloadable = "yes" end
					if (line['button download']) then @track_url    = "http://soundcloud.com#{line.split('href="').last.split('"').first}\n" end
					if (line['This track is not downloadable']) then @downloadable = "no" end
					if (line['class="file-type"'])
						@ext = line.split('</').first.split('>').last
						for excluded_ext in $excluded_exts.split(";").each do 
							if not excluded_ext == "" and @ext =~ /^#{Regexp.escape(excluded_ext)}$/i then @downloadable = "no" end
						end
					end
					if (line['class="content-size"'])
						@size         = line.split('</').first.split('>').last
						if @size.gsub(".","").to_i > $max_size then @downloadable = "no" end 
					end
					if (line['class="duration"']) then @duration = line.split('</').first.split('>').last.gsub(".","").to_i end
					if (line['class="duration"']) and @downloadable == "yes" and @duration > $min_duration and @duration < $max_duration
						filewrite()
					end
				end
			end
		end
	end
	if $verbose == "yes"
		for name in $groups.split(";").each.sort do
			@group = name.chomp
			@page  = 0
			print "\n\n[+] Group: #{@group}\n[+] Leeching pages "
			for i in 1..$max_pages do
				@page = @page+1
				@url  = "http://soundcloud.com/groups/#{@group}/tracks?page=#{@page}"
				print "#{@page}/#{$max_pages}..."
				Net::HTTP.get_response(URI.parse(@url)).body.each_line do |line|
					if (line['class="info-header"'])
						@filename = line.split('</a').first.split('>').last.gsub(/ Artwork$/,'').gsub('"','"').gsub('&','&')
						for excluded_tag in $excluded_tags.split(";").each do 
							if not excluded_tag == "" and @filename[/#{Regexp.escape(excluded_tag)}/i] then @downloadable = "no" end
						end
					end
					if (line['button download']) then @downloadable = "yes" end
					if (line['button download']) then @track_url    = "http://soundcloud.com#{line.split('href="').last.split('"').first}\n" end
					if (line['This track is not downloadable']) then @downloadable = "no" end
					if (line['class="file-type"'])
						@ext = line.split('</').first.split('>').last
						for excluded_ext in $excluded_exts.split(";").each do 
							if not excluded_ext == "" and @ext =~ /^#{Regexp.escape(excluded_ext)}$/i then @downloadable = "no" end
						end
					end
					if (line['class="content-size"'])
						@size         = line.split('</').first.split('>').last
						if @size.gsub(".","").to_i > $max_size then @downloadable = "no" end 
					end
					if (line['class="duration"']) then @duration     = line.split('</').first.split('>').last end
					if (line['class="duration"']) and @downloadable == "yes" and @duration.gsub(".","").to_i > $min_duration and @duration.gsub(".","").to_i < $max_duration
						@info = "\n\nFilename : #{@filename} \nExtension: #{@ext} \nFilesize : #{@size}  \nDuration : #{@duration} minutes\nURL      : #{@track_url}\n"
						filewrite()
					end
				end
			end
		end
	end
end
logo()
get_settings()
main()
__END__
			
			
			
				Nueva versión.
Un saludo!
			
			
			
				Nueva versión 0.3 !!
El script ya no es tán preconfigurado, es más personalizable y todo se lee desde el registro de Windows.
Un nuevo menú con varias opciones:
- Añadir un grupo
- Eliminar un grupo
- Listar los grupos
- Establecer la ruta del log
- Establecer la ruta del archivo leecher
- Eliminar el archivo log
- Eliminar el el archivo leecher
- Establecer el máximo número de páginas a parsear
- Crear un backup de las opciones
PD: He añadido un executable en el comentario principal.
Un saludo!
Saludos
			
 
			
			
				Tenemos que agregar el "Me gusta", así no hay necesidad de publicar :P
Saludos
			
			
			
				Nueva versión 0.4
He añadido una opción para configurar la mínima y máxima duracion aceptada para las pistas de audio, por ejemplo para los que no queremos cojer las urls de sesiones de dj's que duran horas, etc... 
un saludo
			
			
			
				Excelente código gracias por compartirlo.  ;-)
			
			
			
				Cita de: Danyfirex en 16 Noviembre 2012, 20:43 PM
Excelente código gracias por compartirlo.  ;-)
Gracias me alegra que te haya gustado
Nueva versión 0.5Bugs corregidos:
- Las exclusiones por el máximo/mínimo duración de la pista no funcionaban correctamente
Mejoras:
- He optimizado el peso del archivo "log" para que pese la mitad.
- Nueva opción para excluir pistas por su tamaño.
- Nueva opción para excluir pistas por su extensión de archivo.
- Nueva opción para excluir pistas por "tags" en el nombre del archivo.
- Nueva opción para activar el modo verbose, para mostrar más información.
- Otras nuevas opciones algo más técnicas...
- Todas las opciones antiguas y nuevas se han mejorado en general tanto para que séa un entorno de configuración más agradable como para intentar evitar bugs.