diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..162faf7
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,38 @@
+include: package:lints/recommended.yaml
+linter:
+  rules:
+    avoid_print: false
+    prefer_single_quotes: true
+    always_use_package_imports: true
+    no_adjacent_strings_in_list: true
+    unnecessary_statements: true
+    always_declare_return_types: true
+    always_put_required_named_parameters_first: true
+    always_put_control_body_on_new_line: true
+    avoid_escaping_inner_quotes: true
+    avoid_setters_without_getters: true
+    eol_at_end_of_file: true
+    prefer_constructors_over_static_methods: true
+    prefer_expression_function_bodies: true
+    prefer_final_in_for_each: true
+    prefer_final_locals: true
+    prefer_final_parameters: true
+    prefer_foreach: true
+    prefer_if_elements_to_conditional_expressions: true
+    prefer_mixin: true
+    prefer_null_aware_method_calls: true
+    require_trailing_commas: true
+    sized_box_shrink_expand: true
+    sort_constructors_first: true
+    unnecessary_await_in_return: true
+    unnecessary_null_checks: true
+    unnecessary_parenthesis: true
+    use_enums: true
+    use_if_null_to_convert_nulls_to_bools: true
+    use_is_even_rather_than_modulo: true
+    use_late_for_private_fields_and_variables: true
+    use_named_constants: true
+    use_setters_to_change_properties: true
+    use_string_buffers: true
+    use_super_parameters: true
+    use_to_and_as_if_applicable: true
diff --git a/bin/main.dart b/bin/main.dart
new file mode 100644
index 0000000..8d21919
--- /dev/null
+++ b/bin/main.dart
@@ -0,0 +1,16 @@
+import 'dart:core';
+
+import 'package:funkblubber/funkblubber.dart' as funkblubber;
+import 'package:funkblubber/console.dart' as console;
+import 'package:funkblubber/funkentity.dart';
+import 'package:funkblubber/parser.dart' as parser;
+
+void main(final List<String> arguments) async {
+  final object = parser.extract(arguments);
+  if (object.kind == FunkEntity.error) {
+    console.error("'funkblubber --help 'for more");
+    return;
+  }
+
+  await funkblubber.download(object: object);
+}
diff --git a/lib/console.dart b/lib/console.dart
new file mode 100644
index 0000000..1a16dff
--- /dev/null
+++ b/lib/console.dart
@@ -0,0 +1,9 @@
+import 'dart:io';
+
+void error(final String message) {
+  stderr.writeln('error: $message');
+}
+
+void info(final String message) {
+  stdout.writeln(message);
+}
diff --git a/lib/funkblubber.dart b/lib/funkblubber.dart
new file mode 100644
index 0000000..922815f
--- /dev/null
+++ b/lib/funkblubber.dart
@@ -0,0 +1,25 @@
+import 'dart:core';
+import 'package:dio/dio.dart';
+import 'package:funkblubber/funkentity.dart';
+import 'package:funkblubber/console.dart' as console;
+
+Future<void> download({required final FunkObject object}) async {
+  switch (object.kind) {
+    case FunkEntity.album:
+      await _downloadAlbum(object);
+      return;
+
+    default:
+      return;
+  }
+}
+
+Future<void> _downloadAlbum(final FunkObject object) async {
+  final response = await Dio().get(
+    'https://${object.domain}/api/v1/tracks/?'
+    'album=${object.id}&ordering=creation_date&'
+    'page=1&page_size=16&scope=all',
+  );
+
+  for (final songResponse in response.data['results']) {}
+}
diff --git a/lib/funkentity.dart b/lib/funkentity.dart
new file mode 100644
index 0000000..610f374
--- /dev/null
+++ b/lib/funkentity.dart
@@ -0,0 +1,20 @@
+enum FunkEntity {
+  error,
+
+  song,
+  album,
+  artist,
+  profile,
+}
+
+class FunkObject {
+  FunkObject({
+    required this.kind,
+    required this.id,
+    required this.domain,
+  });
+
+  final String domain;
+  final FunkEntity kind;
+  final String id;
+}
diff --git a/lib/parser.dart b/lib/parser.dart
new file mode 100644
index 0000000..f5e10ac
--- /dev/null
+++ b/lib/parser.dart
@@ -0,0 +1,51 @@
+import 'package:funkblubber/funkentity.dart';
+import 'package:funkblubber/console.dart' as console;
+
+FunkObject extract(final List<String> args) {
+  FunkObject result = FunkObject(
+    kind: FunkEntity.error,
+    id: '',
+    domain: '',
+  );
+
+  if (args.isEmpty) {
+    console.error('no arguments provided');
+    return result;
+  }
+
+  try {
+    final Uri uri = Uri.parse(args[0]);
+
+    final segments = uri.pathSegments;
+    for (int i = 0; i < segments.length; ++i) {
+      switch (segments[i]) {
+        case 'artists':
+          result = FunkObject(
+            kind: FunkEntity.artist,
+            id: segments[i + 1],
+            domain: uri.host,
+          );
+          ++i;
+          break;
+
+        case 'album':
+          result = FunkObject(
+            kind: FunkEntity.album,
+            id: segments[i + 1],
+            domain: uri.host,
+          );
+          ++i;
+          break;
+      }
+    }
+  } catch (e) {
+    console.error(e.toString());
+    result = FunkObject(
+      kind: FunkEntity.error,
+      id: '',
+      domain: '',
+    );
+  }
+
+  return result;
+}
diff --git a/pubspec.lock b/pubspec.lock
new file mode 100644
index 0000000..8ab21f3
--- /dev/null
+++ b/pubspec.lock
@@ -0,0 +1,381 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+  _fe_analyzer_shared:
+    dependency: transitive
+    description:
+      name: _fe_analyzer_shared
+      sha256: "0c80aeab9bc807ab10022cd3b2f4cf2ecdf231949dc1ddd9442406a003f19201"
+      url: "https://pub.dev"
+    source: hosted
+    version: "52.0.0"
+  analyzer:
+    dependency: transitive
+    description:
+      name: analyzer
+      sha256: cd8ee83568a77f3ae6b913a36093a1c9b1264e7cb7f834d9ddd2311dade9c1f4
+      url: "https://pub.dev"
+    source: hosted
+    version: "5.4.0"
+  args:
+    dependency: transitive
+    description:
+      name: args
+      sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.2"
+  async:
+    dependency: transitive
+    description:
+      name: async
+      sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.10.0"
+  boolean_selector:
+    dependency: transitive
+    description:
+      name: boolean_selector
+      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
+  collection:
+    dependency: transitive
+    description:
+      name: collection
+      sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.17.0"
+  convert:
+    dependency: transitive
+    description:
+      name: convert
+      sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.1"
+  coverage:
+    dependency: transitive
+    description:
+      name: coverage
+      sha256: "961c4aebd27917269b1896382c7cb1b1ba81629ba669ba09c27a7e5710ec9040"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.6.2"
+  crypto:
+    dependency: transitive
+    description:
+      name: crypto
+      sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.2"
+  dio:
+    dependency: "direct main"
+    description:
+      name: dio
+      sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8"
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.6"
+  file:
+    dependency: transitive
+    description:
+      name: file
+      sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.1.4"
+  frontend_server_client:
+    dependency: transitive
+    description:
+      name: frontend_server_client
+      sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.2.0"
+  glob:
+    dependency: transitive
+    description:
+      name: glob
+      sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
+  http_multi_server:
+    dependency: transitive
+    description:
+      name: http_multi_server
+      sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.2.1"
+  http_parser:
+    dependency: transitive
+    description:
+      name: http_parser
+      sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.2"
+  io:
+    dependency: transitive
+    description:
+      name: io
+      sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.4"
+  js:
+    dependency: transitive
+    description:
+      name: js
+      sha256: "323b7c70073cccf6b9b8d8b334be418a3293cfb612a560dc2737160a37bf61bd"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.6.6"
+  lints:
+    dependency: "direct dev"
+    description:
+      name: lints
+      sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.1"
+  logging:
+    dependency: transitive
+    description:
+      name: logging
+      sha256: c0bbfe94d46aedf9b8b3e695cf3bd48c8e14b35e3b2c639e0aa7755d589ba946
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.0"
+  matcher:
+    dependency: transitive
+    description:
+      name: matcher
+      sha256: c94db23593b89766cda57aab9ac311e3616cf87c6fa4e9749df032f66f30dcb8
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.12.14"
+  meta:
+    dependency: transitive
+    description:
+      name: meta
+      sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.8.0"
+  mime:
+    dependency: transitive
+    description:
+      name: mime
+      sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.4"
+  node_preamble:
+    dependency: transitive
+    description:
+      name: node_preamble
+      sha256: "8ebdbaa3b96d5285d068f80772390d27c21e1fa10fb2df6627b1b9415043608d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.1"
+  package_config:
+    dependency: transitive
+    description:
+      name: package_config
+      sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.0"
+  path:
+    dependency: transitive
+    description:
+      name: path
+      sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.8.3"
+  pool:
+    dependency: transitive
+    description:
+      name: pool
+      sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.5.1"
+  pub_semver:
+    dependency: transitive
+    description:
+      name: pub_semver
+      sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.3"
+  shelf:
+    dependency: transitive
+    description:
+      name: shelf
+      sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.4.0"
+  shelf_packages_handler:
+    dependency: transitive
+    description:
+      name: shelf_packages_handler
+      sha256: aef74dc9195746a384843102142ab65b6a4735bb3beea791e63527b88cc83306
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.1"
+  shelf_static:
+    dependency: transitive
+    description:
+      name: shelf_static
+      sha256: e792b76b96a36d4a41b819da593aff4bdd413576b3ba6150df5d8d9996d2e74c
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.1"
+  shelf_web_socket:
+    dependency: transitive
+    description:
+      name: shelf_web_socket
+      sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.3"
+  source_map_stack_trace:
+    dependency: transitive
+    description:
+      name: source_map_stack_trace
+      sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
+  source_maps:
+    dependency: transitive
+    description:
+      name: source_maps
+      sha256: "490098075234dcedb83c5d949b4c93dad5e6b7702748de000be2b57b8e6b2427"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.10.11"
+  source_span:
+    dependency: transitive
+    description:
+      name: source_span
+      sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.9.1"
+  stack_trace:
+    dependency: transitive
+    description:
+      name: stack_trace
+      sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.11.0"
+  stream_channel:
+    dependency: transitive
+    description:
+      name: stream_channel
+      sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
+  string_scanner:
+    dependency: transitive
+    description:
+      name: string_scanner
+      sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.0"
+  term_glyph:
+    dependency: transitive
+    description:
+      name: term_glyph
+      sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.1"
+  test:
+    dependency: "direct dev"
+    description:
+      name: test
+      sha256: b54d427664c00f2013ffb87797a698883c46aee9288e027a50b46eaee7486fa2
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.22.2"
+  test_api:
+    dependency: transitive
+    description:
+      name: test_api
+      sha256: "6182294da5abf431177fccc1ee02401f6df30f766bc6130a0852c6b6d7ee6b2d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.4.18"
+  test_core:
+    dependency: transitive
+    description:
+      name: test_core
+      sha256: "95ecc12692d0dd59080ab2d38d9cf32c7e9844caba23ff6cd285690398ee8ef4"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.4.22"
+  typed_data:
+    dependency: transitive
+    description:
+      name: typed_data
+      sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.3.1"
+  vm_service:
+    dependency: transitive
+    description:
+      name: vm_service
+      sha256: d069ad658b700fc5fb774771ac8997f226ca29a45e0a450776fff3d969c8ba8f
+      url: "https://pub.dev"
+    source: hosted
+    version: "10.1.0"
+  watcher:
+    dependency: transitive
+    description:
+      name: watcher
+      sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.2"
+  web_socket_channel:
+    dependency: transitive
+    description:
+      name: web_socket_channel
+      sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.0"
+  webkit_inspection_protocol:
+    dependency: transitive
+    description:
+      name: webkit_inspection_protocol
+      sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.0"
+  yaml:
+    dependency: transitive
+    description:
+      name: yaml
+      sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.1"
+sdks:
+  dart: ">=2.19.0 <4.0.0"
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 0000000..7e3f413
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,13 @@
+name: funkblubber
+description: A simple CLI for Funkwhale
+version: 0.1.0
+
+environment:
+  sdk: '>=2.19.0 <3.0.0'
+
+dev_dependencies:
+  lints: ^2.0.0
+  test: ^1.21.0
+
+dependencies:
+  dio: ^4.0.6
diff --git a/test/funkblubber_test.dart b/test/funkblubber_test.dart
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/funkblubber_test.dart
@@ -0,0 +1 @@
+