Setup tools for music organisation
This commit is contained in:
parent
dc59b9a37e
commit
7a15e2b981
22
README.md
22
README.md
@ -144,3 +144,25 @@ not being accessed/modified during this process. It is easy to access `yggdrasil
|
||||
```sh
|
||||
python scripts/scaleway/baldur.py delete
|
||||
```
|
||||
|
||||
## Music organisation
|
||||
|
||||
The `playbooks/music.yml` playbook sets up tools and configuration for organising music. The process
|
||||
is manual though. The steps for adding a new CD.
|
||||
|
||||
All steps below are to be executed as the `music` user.
|
||||
|
||||
### Ripping a CD
|
||||
|
||||
1. Use a CD ripper and rip the CD to `/var/lib/yggdrasil/home/music/rip` using flac encoding.
|
||||
2. Samba has been set up to give Windows access to the above directory. Therefore, CD rippers
|
||||
available only for Windows can also be used, e.g. dBpoweramp.
|
||||
|
||||
### Import new music
|
||||
|
||||
1. Run `beet import /var/lib/yggdrasil/home/music/rip`. This will move the music files to
|
||||
`/var/lib/yggdrasil/data/music/flac`.
|
||||
2. Run `beet convert <match>`, where `<match>` is used to narrow down to new music only. This will
|
||||
convert the flac files into mp3 files for sharing via Nextcloud.
|
||||
3. Run `nextcloud-upload /var/tmp/music/mp3/<artist>` for every artist to upload to Nextcloud.
|
||||
4. Remove the `/var/tmp/music/mp3/<artist>` directory.
|
||||
|
@ -98,11 +98,21 @@ music_user_data_directory: "{{ system_var_data_directory }}/{{ music_user_name }
|
||||
music_user_home_dataset: "rpool{{ music_user_home_directory }}"
|
||||
music_user_data_dataset: "rpool{{ music_user_data_directory }}"
|
||||
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
# music:backups
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
music_user_backups_snapshots_data_dataset: "\
|
||||
{{ system_backups_snapshots_data_dataset }}/{{ music_user_name }}"
|
||||
music_user_backups_snapshots_recursive: true
|
||||
music_user_backups_snapshots_skip_parent: true
|
||||
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
# music:org
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
music_user_nextcloud_url: "https://cloud.wojciechkozlowski.eu/public.php/webdav"
|
||||
music_user_nextcloud_user: "{{ vault_music_user_nextcloud_user }}"
|
||||
music_user_nextcloud_pswd: "{{ vault_music_user_nextcloud_pswd }}"
|
||||
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
# services
|
||||
# --------------------------------------------------------------------------------------------------
|
||||
|
@ -35,5 +35,5 @@
|
||||
- "music:backups"
|
||||
- "music:backups:restic"
|
||||
- "music:backups:restic:user"
|
||||
# - role: "music/org"
|
||||
# tags: "music:org"
|
||||
- role: "music/org"
|
||||
tags: "music:org"
|
||||
|
93
playbooks/roles/music/org/files/nextcloud-upload
Executable file
93
playbooks/roles/music/org/files/nextcloud-upload
Executable file
@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import requests
|
||||
import requests.auth
|
||||
import urllib
|
||||
import urllib.parse
|
||||
import yaml
|
||||
|
||||
|
||||
class WebDavManager:
|
||||
|
||||
def __init__(self, url, user, pswd):
|
||||
self.__url = url
|
||||
self.__auth = requests.auth.HTTPBasicAuth(user, pswd)
|
||||
|
||||
@staticmethod
|
||||
def __remote_path(dstdir, dst):
|
||||
path = []
|
||||
if dstdir is not None:
|
||||
path.append(dstdir.strip('/'))
|
||||
path.append(dst.strip('/'))
|
||||
return '/'.join(path)
|
||||
|
||||
def __url_path(self, dstdir, dst):
|
||||
return '/'.join([
|
||||
self.__url.strip('/'),
|
||||
urllib.parse.quote(self.__remote_path(dstdir, dst)),
|
||||
])
|
||||
|
||||
def mkdir(self, dstdir, dir):
|
||||
print(f"mkdir: {self.__remote_path(dstdir, dir)}", flush=True)
|
||||
|
||||
rc = requests.request("MKCOL", self.__url_path(dstdir, dir), auth=self.__auth)
|
||||
print(f"response: {rc}", flush=True)
|
||||
|
||||
if ((rc.status_code // 100) != 2) and (rc.status_code != 405):
|
||||
raise RuntimeError(f"unexpected response ({rc}) to MKCOL ({rc.url}):\n{rc.text}")
|
||||
|
||||
def upload_file(self, srcdir, dstdir, file):
|
||||
print(f"upload: {self.__remote_path(dstdir, file)}", flush=True)
|
||||
|
||||
with open(os.path.join(srcdir, file), "rb") as fobj:
|
||||
rc = requests.put(self.__url_path(dstdir, file), auth=self.__auth, data=fobj)
|
||||
print(f"response: {rc}", flush=True)
|
||||
|
||||
if (rc.status_code // 100) != 2:
|
||||
raise RuntimeError(f"unexpected response ({rc}) to PUT ({rc.url}):\n{rc.text}")
|
||||
|
||||
@staticmethod
|
||||
def __walkraise(error):
|
||||
raise error
|
||||
|
||||
def upload_dir(self, target):
|
||||
prefix = os.path.dirname(os.path.realpath(target))
|
||||
self.mkdir(None, os.path.relpath(target, prefix))
|
||||
|
||||
for root, dirs, files in os.walk(target, topdown=True, onerror=self.__walkraise):
|
||||
for dir in dirs:
|
||||
self.mkdir(os.path.relpath(root, prefix), dir)
|
||||
for file in files:
|
||||
self.upload_file(root, os.path.relpath(root, prefix), file)
|
||||
|
||||
def upload(self, target):
|
||||
if os.path.isfile(target):
|
||||
self.upload_file(
|
||||
os.path.dirname(os.path.realpath(args.target)),
|
||||
None,
|
||||
os.path.basename(args.target),
|
||||
)
|
||||
else:
|
||||
assert os.path.isdir(target)
|
||||
self.upload_dir(target)
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="upload files to nextcloud")
|
||||
|
||||
parser.add_argument("--config", type=str, default="~/.config/nextcloud-upload/config.yml",
|
||||
help="path to configuration")
|
||||
parser.add_argument("target", type=str, help="file or folder to upload")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.config, encoding="utf-8") as config_file:
|
||||
config = yaml.safe_load(config_file)
|
||||
|
||||
for key in ["url", "user", "pswd"]:
|
||||
if key not in config:
|
||||
raise KeyError(f"{key} must be present in {args.config}")
|
||||
|
||||
webdav = WebDavManager(config["url"], config["user"], config["pswd"])
|
||||
webdav.upload(args.target)
|
13
playbooks/roles/music/org/meta/argument_specs.yml
Normal file
13
playbooks/roles/music/org/meta/argument_specs.yml
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
argument_specs:
|
||||
main:
|
||||
options:
|
||||
music_user_name:
|
||||
type: "str"
|
||||
required: true
|
||||
music_user_home_directory:
|
||||
type: "str"
|
||||
required: true
|
||||
music_user_data_directory:
|
||||
type: "str"
|
||||
required: true
|
52
playbooks/roles/music/org/tasks/main.yml
Normal file
52
playbooks/roles/music/org/tasks/main.yml
Normal file
@ -0,0 +1,52 @@
|
||||
---
|
||||
- name: "install beets"
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "beets"
|
||||
- "ffmpeg"
|
||||
|
||||
- name: "install nextcloud-upload"
|
||||
ansible.builtin.copy:
|
||||
src: "./nextcloud-upload"
|
||||
dest: "/usr/local/bin/nextcloud-upload"
|
||||
mode: 0755
|
||||
|
||||
- block:
|
||||
|
||||
- name: "create beets config directory"
|
||||
ansible.builtin.file:
|
||||
path: "{{ music_user_home_directory }}/.config/beets"
|
||||
state: "directory"
|
||||
owner: "{{ music_user_name }}"
|
||||
group: "{{ music_user_name }}"
|
||||
mode: 0755
|
||||
|
||||
- name: "create beets convert directory"
|
||||
ansible.builtin.file:
|
||||
path: "/var/tmp/{{ music_user_name }}/mp3"
|
||||
state: "directory"
|
||||
owner: "{{ music_user_name }}"
|
||||
group: "{{ music_user_name }}"
|
||||
mode: 0755
|
||||
|
||||
- name: "configure beets"
|
||||
ansible.builtin.template:
|
||||
src: "./beets.yml"
|
||||
dest: "{{ music_user_home_directory }}/.config/beets/config.yaml"
|
||||
mode: 0644
|
||||
|
||||
- name: "create nextcloud-upload config directory"
|
||||
ansible.builtin.file:
|
||||
path: "{{ music_user_home_directory }}/.config/nextcloud-upload"
|
||||
state: "directory"
|
||||
owner: "{{ music_user_name }}"
|
||||
group: "{{ music_user_name }}"
|
||||
mode: 0755
|
||||
|
||||
- name: "configure nextcloud-upload"
|
||||
ansible.builtin.template:
|
||||
src: "./nextcloud-upload.yml"
|
||||
dest: "{{ music_user_home_directory }}/.config/nextcloud-upload/config.yml"
|
||||
mode: 0644
|
||||
|
||||
become_user: "{{ music_user_name }}"
|
10
playbooks/roles/music/org/templates/beets.yml
Normal file
10
playbooks/roles/music/org/templates/beets.yml
Normal file
@ -0,0 +1,10 @@
|
||||
plugins: convert
|
||||
library: {{ music_user_data_directory }}/flac/library.db
|
||||
|
||||
directory: {{ music_user_data_directory }}/flac
|
||||
import:
|
||||
move: yes
|
||||
write: no
|
||||
|
||||
convert:
|
||||
dest: /var/tmp/{{ music_user_name }}/mp3
|
3
playbooks/roles/music/org/templates/nextcloud-upload.yml
Normal file
3
playbooks/roles/music/org/templates/nextcloud-upload.yml
Normal file
@ -0,0 +1,3 @@
|
||||
url: "{{ music_user_nextcloud_url }}"
|
||||
user: "{{ music_user_nextcloud_user }}"
|
||||
pswd: "{{ music_user_nextcloud_pswd }}"
|
Loading…
Reference in New Issue
Block a user