Last active
October 1, 2018 18:37
-
-
Save SkyzohKey/3dfc0a529958732e1e4267d602770c6b to your computer and use it in GitHub Desktop.
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
/** | |
* valac -o bandcamp-downloader --pkg libsoup-2.4 --pkg json-glib-1.0 --pkg posix main.vala | |
* ./bandcamp-downloader --band=bash38 --album=summer-time -o ~/Music/bash-summer-time | |
**/ | |
private static string band_name = null; | |
private static string album_name = null; | |
private static string save_path = null; | |
private const GLib.OptionEntry[] options = { | |
{ "band", 'b', 0, OptionArg.STRING, ref band_name, "Name of the bandcamp page", "BANDNAME" }, | |
{ "album", 'a', 0, OptionArg.STRING, ref album_name, "Name of the bandcamp album", "ALBUM" }, | |
{ "directory", 'o', 0, OptionArg.FILENAME, ref save_path, "Directory where to save .mp3", "DESTDIR" }, | |
{ null } // List terminator. | |
}; | |
public static int main (string[] args) { | |
var opt_context = new OptionContext ("- Bandcamp downloader"); | |
try { | |
opt_context.set_summary ("A simple Bandcamp downloader to grab .mp3 albums."); | |
opt_context.set_help_enabled (true); | |
opt_context.add_main_entries (options, null); | |
opt_context.parse (ref args); | |
} catch (OptionError e) { | |
stdout.printf ("error: %s\n", e.message); | |
stdout.printf ("Run '%s --help' to see a full list of available command line options.\n", args[0]); | |
return 0; | |
} | |
if (band_name == null || album_name == null) { | |
print (opt_context.get_help (true, null) + "\n"); | |
return 0; | |
} | |
if (save_path == null) { | |
string music_dir = Environment.get_user_special_dir (UserDirectory.MUSIC); | |
save_path = @"$music_dir/$album_name"; | |
log ("I", @"Downloads will be stored in: $save_path/"); | |
} | |
DirUtils.create_with_parents (save_path, 0755); | |
var band_uri = @"https://$(band_name).bandcamp.com/album/$(album_name)"; | |
var session = new Soup.Session (); | |
session.user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36"; | |
var parser = new Json.Parser (); | |
var parser_meta = new Json.Parser (); | |
uint8[] data; | |
try { | |
File.new_for_uri (band_uri).load_contents (null, out data, null); | |
} catch (Error e) { | |
log ("E", @"Album \"$album_name\" $(e.message)", true); | |
return 0; | |
} | |
string json = (string)data; | |
json = json.substring (json.index_of ("trackinfo :") + 11); | |
json = json.substring (json.index_of ("[")); | |
json = json.substring (0, json.index_of ("],") + 1); | |
string meta = (string)data; | |
meta = meta.substring (meta.index_of ("current: ") + 9); | |
meta = meta.substring (0, meta.index_of ("},") + 1); | |
string artist = (string)data; | |
artist = artist.substring (artist.index_of ("artist: \"") + 9); | |
artist = artist.substring (0, artist.index_of ("\"")); | |
string cover_uri = (string)data; | |
cover_uri = cover_uri.substring (cover_uri.index_of ("artFullsizeUrl: \"") + 17); | |
cover_uri = cover_uri.substring (0, cover_uri.index_of ("\"")); | |
try { | |
parser.load_from_data (json); | |
parser_meta.load_from_data (meta); | |
} catch (Error e) { | |
log ("E", @"Cannot load album JSON from bandcamp: $(e.message)", true); | |
return 0; | |
} | |
var album = parser_meta.get_root ().get_object ().get_string_member ("title"); | |
//var artist = parser_meta.get_root ().get_object ().get_string_member ("artist"); | |
log ("I", @"Started to download \"$album\" by $artist", true); | |
log ("I", @"Downloading from: $band_uri"); | |
var tracks = parser.get_root().get_array(); | |
var tracks_count = (cover_uri == "") ? tracks.get_length () : tracks.get_length () + 1; | |
tracks.foreach_element ((array, index, node) => { | |
var object = node.get_object(); | |
if (object.get_member ("file").get_node_type() == Json.NodeType.NULL) | |
return; | |
var track_num = object.get_int_member ("track_num"); | |
var title = object.get_string_member ("title"); | |
string path = "%s/%lld. %s.mp3".printf (save_path, track_num, title); | |
string ipath = "http:" + object.get_object_member ("file").get_string_member ("mp3-128"); | |
var message = new Soup.Message ("GET", ipath); | |
session.send_message (message); | |
log (@"OK [$track_num/$tracks_count]", @"$title"); | |
try { | |
FileUtils.set_data (path, message.response_body.data); | |
} catch (FileError e) { | |
log ("E", @"Cannot save file: $(e.message)", true); | |
} | |
}); | |
// Download the album cover if any. | |
if (cover_uri != "") { | |
string path = "%s/cover.jpg".printf (save_path); | |
var message = new Soup.Message ("GET", cover_uri); | |
session.send_message (message); | |
log (@"OK [$tracks_count/$tracks_count]", @"cover.jpg"); | |
try { | |
FileUtils.set_data (path, message.response_body.data); | |
} catch (FileError e) { | |
log ("E", @"Cannot save file: $(e.message)", true); | |
} | |
} | |
log ("I", @"The album \"$album\" was successfuly downloaded.", true); | |
log ("I", @"You'll find the downloaded files in $save_path", true); | |
return 0; | |
} | |
private void log (string type, string message, bool full = false) { | |
if (Posix.isatty (stdout.fileno()) == false) { | |
stdout.printf (@"$type: $message\n"); | |
return; | |
} | |
var success = "\x1B[32m\x1B[1m"; | |
var info = "\x1B[34m\x1B[1m"; | |
var error = "\x1B[31m\x1B[1m"; | |
var normal = "\x1B[0m"; | |
if (full) { | |
normal = ""; | |
} | |
if (type.index_of("OK") == 0) { | |
stdout.printf (@"$success$type:$normal $message\n"); | |
} else if (type == "I") { | |
stdout.printf (@"$info$type:$normal $message\n"); | |
} else if (type == "E") { | |
stdout.printf (@"$error$type:$normal $message\n"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment