Skip to content

Instantly share code, notes, and snippets.

@SkyzohKey
Last active October 1, 2018 18:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SkyzohKey/3dfc0a529958732e1e4267d602770c6b to your computer and use it in GitHub Desktop.
Save SkyzohKey/3dfc0a529958732e1e4267d602770c6b to your computer and use it in GitHub Desktop.
/**
* 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