Git Product home page Git Product logo

betanin's Introduction

beets.io based man-in-the-middle of your torrent client and music player


workflow


notifiers

betanin uses apprise for notifications. so anything supported there will work. but some include

  • email
  • discord
  • telegram
  • emby

installation

pip install --user betanin

usage

# start server
betanin
# a config file will be created, add your credentials to it
# start again
betanin [--host=<host>] [--port=<port>]
# ui will be available at port
# you may also use env vars instead, eg
BETANIN_HOST=0.0.0.0 betanin
BETANIN_PORT=4030 betanin

# optionally start cli (for db operations, debugging)
betanin-shell
# or if docker
docker exec -it <container_id> betanin-shell

screenshots


docker

image

docker pull sentriz/betanin

volumes /b/.local/share/betanin/ for a persistent database

/b/.config/betanin/ for a persistent betanin config
/b/.config/beets/ for a persistent beets home (point this to your current beets home if you have one)
/music/ so beets can access your music
/downloads/ so beets can access your downloads

compose
betanin:
  image: sentriz/betanin
  ports:
    - 9393:9393
  restart: unless-stopped
  environment:
    - UID=1000 # (optionally) set user id
    - GID=1000 # (optionally) set group id
  volumes:
    - ${DATA}/betanin/data:/b/.local/share/betanin/
    - ${DATA}/betanin/config:/b/.config/betanin/
    - ${DATA}/betanin/beets:/b/.config/beets/
    - ${MEDIA}/music:/music/
    - ${MEDIA}/downloads:/downloads/

transmission

create a script named done.sh or anything you like, and make it executable:
chmod +x done.sh

settings.json (example excerpt)
...
"script-torrent-done-enabled": true,
"script-torrent-done-filename": "/scripts/done.sh",
...
done script
#!/bin/sh

curl \
    --request POST \
    --data-urlencode "path=<path_to_transmission_downloads>" \
    --data-urlencode "name=$TR_TORRENT_NAME" \
    --header "X-API-Key: <your_api_key>" \
    "https://betanin.example.com/api/torrents"
transmission docker compose (excerpt)
volumes:
  - ${DATA}/transmission/config:/config
  - ${DATA}/transmission/scripts:/scripts
  - ${MEDIA}/download:/downloads

deluge

create a script named done.sh or anything you like, and make it executable:
chmod +x done.sh
you must also be using the Execute plugin, set to the Torrent Complete event

done script
#!/bin/sh

curl \
    --request POST \
    --data-urlencode "path=<path_to_deluge_downloads>" \
    --data-urlencode "name=$2" \
    --header "X-API-Key: <your_api_key>" \
    "https://betanin.example.com/api/torrents"

qbittorrent

create a script named done.sh or anything you like, and make it executable:
chmod +x done.sh

open qbittorrent Tools > Options > check Run external program on torrent completion

set the path to the above done.sh and arguments such as

/path/to/done.sh "%L" "%R"
done script
#!/bin/sh

echo "category: $1"
echo "path: $2"

[ "$1" != "music" ] && exit

curl \
    --request POST \
    --data-urlencode "both=$2" \
    --header "X-API-Key: <your_api_key>" \
    "https://betanin.example.com/api/torrents"

now any music downloaded to the music category will be imported by betanin


developing

working on the backend

there is not much else to do, write your code, python -m betanin.entry.betanin, kill it, write your code, etc. the webserver will be available at http://localhost:9393/. the static frontend is served at /, and the api is served at /api. (there is a swagger ui there too) also see python -m betanin.entry.shell.
if you need to do a manual migration do env FLASK_APP='betanin.application:create' flask db migrate --directory betanin_migrations/ (then upgrades are automatically done on betanin start)

working on the frontend

start the backend with python -m betanin.entry.betanin, but don’t use the static frontend served at http://localhost:9393/. Instead, in a new shell, do npm --prefix betanin_client/ run serve and use the frontend served at http://localhost:8081/. it will look for a backend listening on port 9393 locally. after that you can edit anything in betanin_client/src, it will be linted and automatically reflected in your web browser.

betanin's People

Contributors

dependabot[bot] avatar github-actions[bot] avatar izaakf avatar jee-r avatar mod242 avatar sentriz avatar tandy-1000 avatar w1ldg00se avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

betanin's Issues

Add example Lidarr Connect script

Would a Lidarr setup example be worth adding to the settings page alongside the examples for Transmission and Deluge?

I've been working on getting Lidarr to send new imports to Betanin. It's been a long road, but I've got a basic workflow going in my environment. While I'm running my fork with the changes proposed in #34, I think a Lidarr script would work even without those changes.

The two Reddit discussions linked below have been really helpful getting this set up. They're tailored for calling beet import in the post-import script, but can be adjusted to work with Betanin.

https://www.reddit.com/r/Lidarr/comments/c1enh9/beets_lidarr/
https://www.reddit.com/r/Lidarr/comments/i4844t/anyone_got_a_working_lidarrbeets_workflow/

Can't get it to work - Wrong volume paths in the container?

Hi

Betanin and Beets running from the same stack in Portainer

version: "2.1"
services:
  beets:
    image: lscr.io/linuxserver/beets:latest
    container_name: beets
    environment:
      - PUID=1001
      - PGID=1001
      - TZ=Europe/Brussels
    volumes:
      - /media/seedbox/.config/beets:/config
      - /nfs/media/musique:/music
      - /media/seedbox/slskdownloads/complete:/downloads
    ports:
      - 8337:8337
    restart: unless-stopped

  betanin:
    image: sentriz/betanin
    container_name: betanin
    ports:
      - 9393:9393
    restart: unless-stopped
    environment:
      - UID=1001
      - GID=1001
      - TZ=Europe/Brussels
    volumes:
      - /media/seedbox/.config/betanin/data/:/b/.local/share/betanin/
      - /media/seedbox/.config/betanin/config/:/b/.config/betanin/
      - /media/seedbox/.config/beets/:/b/.config/beets/
      - /nfs/media/musique:/music
      - /media/seedbox/slskdownloads/complete:/downloads    

Beets work perfectly. ie when I run the import task with
docker exec -u abc -it beets /bin/bash -c 'beet import /downloads'
It starts the import, parse the downloads, ask me questions, move files.

But import task is failing in Betanin
There's not a hint of issue that could lead me on the right track.
When I start everything from scratch, betanin starts without error, creates config file in /config folder, and betanin.db and secret_key in /data folder.

Everything looks OK in the web GUI, and in the settings/beet config, I can see my beets config.yaml which prove that folders are correctly set.
The 2 containers are properly running with the same user "seedbox" and following all my debugging, I even granted a chmod 777 on both folders.
image

When I go in betanin torrent GUI, I can browse everything
image

But looks at what happens when I run the import task

image

[betanin] starting cli program

/usr/lib/python3.11/site-packages/beetsplug/extrafiles.py:12: UserWarning: beets.mediafile is deprecated; use mediafile instead
  import beets.mediafile

The database directory /config does not                        exist. Create it (Y/n)? 

First, this makes no sense at all. All directories exists. And I can browse the config directories I defined in the container volume, using the torrent GUI.

If I answer N, I have this

image

Since it is seems to be looking for the file /config/musiclibrary.blb, I assume it can't find the config folder of beets.
But it is there, and the DB is there too. And it has access to it because its the same owner
image

Also the complete nonsense is, as explained before, that I can see the beets config file in the betanin settings. So it is obvsious that it can access it and that my container volumes config is correct.

If I answer Y, I have this
image

And it makes no sense. it can't have a permission denied if its is working on the folders defined in the docker-compose volumes. The user running the 2 containers are the same a,d I triple checked all permissions and ownership are correct on the real linux folders.

So all this make me think that the issue is not on my side.

Cheers.

"gevent.exceptions.LoopExit: This operation would block forever" when tried to launch dev server

I'm willing to do small development for betanin.

I cloned github repo and tried to launch server.

I created venv, installed requirements, plus some other missing dependencies when I tried to launch it.... But I can't fight this one.

(venv) qbus@DESKTOP-CA07ILV:~/betanin-dev/betanin$ python3 -m betanin.entry.betanin
2024-01-24 21:37:20.524 | INFO     | __main__:_print_meta_info:34 - platform - Linux-5.15.133.1-microsoft-standard-WSL2-x86_64-with-glibc2.35
2024-01-24 21:37:20.525 | INFO     | __main__:_print_meta_info:34 - python_version - 3.10.12
2024-01-24 21:37:20.525 | INFO     | __main__:_print_meta_info:34 - betanin_version - v0.5.6

2024-01-24 21:37:20.525 | INFO     | __main__:_ensure_config:61 - using config `/home/qbus/.config/betanin/config.toml`
2024-01-24 21:37:20.525 | INFO     | __main__:_ensure_secret_key:93 - using secret key `/home/qbus/.local/share/betanin/secret_key`
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
2024-01-24 21:37:20.587 | INFO     | __main__:_start_job:101 - starting job betanin.jobs.import_torrents ()
2024-01-24 21:37:20.587 | INFO     | __main__:_start_job:101 - starting job betanin.jobs.serve_web ('', 9393)
Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/qbus/betanin-dev/betanin/betanin/entry/betanin.py", line 146, in <module>
    main(None, None)
  File "/home/qbus/betanin-dev/betanin/venv/lib/python3.10/site-packages/click/core.py", line 1157, in __call__
    return self.main(*args, **kwargs)
  File "/home/qbus/betanin-dev/betanin/venv/lib/python3.10/site-packages/click/core.py", line 1078, in main
    rv = self.invoke(ctx)
  File "/home/qbus/betanin-dev/betanin/venv/lib/python3.10/site-packages/click/core.py", line 1434, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/qbus/betanin-dev/betanin/venv/lib/python3.10/site-packages/click/core.py", line 783, in invoke
    return __callback(*args, **kwargs)
  File "/home/qbus/betanin-dev/betanin/betanin/entry/betanin.py", line 137, in main
    gevent.joinall(
  File "src/gevent/greenlet.py", line 1065, in gevent._gevent_cgreenlet.joinall
  File "src/gevent/greenlet.py", line 1075, in gevent._gevent_cgreenlet.joinall
  File "src/gevent/_hub_primitives.py", line 250, in gevent._gevent_c_hub_primitives.wait_on_objects
  File "src/gevent/_hub_primitives.py", line 287, in gevent._gevent_c_hub_primitives.wait_on_objects
  File "src/gevent/_hub_primitives.py", line 185, in gevent._gevent_c_hub_primitives._WaitIterator.__next__
  File "src/gevent/_hub_primitives.py", line 176, in gevent._gevent_c_hub_primitives._WaitIterator.__next__
  File "src/gevent/_waiter.py", line 195, in gevent._gevent_c_waiter.MultipleWaiter.get
  File "src/gevent/_waiter.py", line 154, in gevent._gevent_c_waiter.Waiter.get
  File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_greenlet_primitives.py", line 65, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch
  File "src/gevent/_gevent_c_greenlet_primitives.pxd", line 35, in gevent._gevent_c_greenlet_primitives._greenlet_switch
gevent.exceptions.LoopExit: This operation would block forever
        Hub: <Hub '' at 0x7fa5c1319e90 epoll default pending=0 ref=0 fileno=4 thread_ident=0x7fa5c436f000>
        Handles:
[]
(venv) qbus@DESKTOP-CA07ILV:~/betanin-dev/betanin$ 

Feature: Single sign-on (SSO) support

It would be nice to be able to use tools like authentik or Authelia as single sign-on providers by implementing e.g. HTTP basic authentication, forward authentication or OpenID Connect.

Change music and download location

Is it possible to configure a different location for the path to my music library and my downloads location? I would like to use beets outside of this application and I don't use /music and /downloads

No notifications when input is needed

I have installed the latest docker image and don't get notified when an import needs input. I get a notified though, when an album get's successfully imported. Is there anything I need to configure other than a notification service?

How handle parrallel jobs with long beets process import

Hi,

My beets import process is very long :

First as usual beets search for candidates (musicbrainz, bandcamp etc...) and if a candidate match then :

  • fetch metadata
  • fetch art
  • chroma
  • replaygain
  • copy in my media directory

If releases are imported one by one num_parallel_jobs = 1 there is no problem but this block all following imports if Betanin need a manual input as long as i resolve it so it's not the best way to import automatically.

if i set num_parallel_jobs = 4 for example, and if multiple import task are running in parallel i have the following issue :

[betanin] starting cli program

/torrents/seed/Music/Neil Young & Crazy Horse - Barn [Reprise 093624878438]  (2021) flac (10 items)

Tagging:
    Neil Young & Crazy Horse - Barn
URL:
    https://musicbrainz.org/release/67908d6d-8dc7-4eb2-98ca-a1b1b75c2e54
(Similarity: 99.7%) (tracks) (Digital Media, 2021, XW, Reprise Records)
 * Song Of The Seasons           -> Song of the Seasons
 * Change Ain't Never Gonna Come -> Change Ain’t Never Gonna (title)
 * Shape Of You                  -> Shape of You
 * Tumblin' Thru The Years       -> Tumblin’ Thru the Years
 * Don't Forget Love             -> Don’t Forget Love

Traceback (most recent call last):
  File "/usr/bin/beet", line 33, in 

    sys.exit(load_entry_point('beets==1.5.1', 'console_scripts', 'beet')())
  File "/usr/lib/python3.9/site-packages/beets/ui/__init__.py", line 1284, in main
    _raw_main(args)
  File "/usr/lib/python3.9/site-packages/beets/ui/__init__.py", line 1271, in _raw_main
    subcommand.func(lib, suboptions, subargs)
  File "/usr/lib/python3.9/site-packages/beets/ui/commands.py", line 973, in import_func
    import_files(lib, paths, query)
  File "/usr/lib/python3.9/site-packages/beets/ui/commands.py", line 943, in import_files
    session.run()
  File "/usr/lib/python3.9/site-packages/beets/importer.py", line 340, in run
    pl.run_parallel(QUEUE_SIZE)
  File "/usr/lib/python3.9/site-packages/beets/util/pipeline.py", line 446, in run_parallel
    raise exc_info[1].with_traceback(exc_info[2])
  File "/usr/lib/python3.9/site-packages/beets/util/pipeline.py", line 311, in run
    out = self.coro.send(msg)
  File "/usr/lib/python3.9/site-packages/beets/util/pipeline.py", line 170, in coro
    task = func(*(args + (task,)))
  File "/usr/lib/python3.9/site-packages/beets/importer.py", line 1444, in user_query
    apply_choice(session, task)
  File "/usr/lib/python3.9/site-packages/beets/importer.py", line 1515, in apply_choice
    task.add(session.lib)
  File "/usr/lib/python3.9/site-packages/beets/importer.py", line 773, in add
    self.record_replaced(lib)
  File "/usr/lib/python3.9/site-packages/beets/importer.py", line 788, in record_replaced
    dup_items = list(lib.items(
  File "/usr/lib/python3.9/site-packages/beets/library.py", line 1526, in items
    return self._fetch(Item, query, sort or self.get_default_item_sort())
  File "/usr/lib/python3.9/site-packages/beets/library.py", line 1500, in _fetch
    return super()._fetch(
  File "/usr/lib/python3.9/site-packages/beets/dbcore/db.py", line 1094, in _fetch
    flex_rows = tx.query(flex_sql, subvals)
  File "/usr/lib/python3.9/site-packages/beets/dbcore/db.py", line 858, in query
    cursor = self.db._connection().execute(statement, subvals)
sqlite3.OperationalError: database is locked

[betanin] program finished with exit status `0`

The first import task locked the beets database and all others imports will failed with exit status 0

do you know how i can solve this issue ? it's not easy to explain this issue i hope it's understandable enough

--
Ps: thank you very much for betanin it's an awesome tool

Update beets to V1.61 (git)

Hi sentriz,

Beets V1.6.0 has not been updated since November of 2021. When you pull the release zip to setup betanin, beets is stuck on the old V1.6.0 version.

I'd like to propose a simple change to requirements-docker.txt.

Since beets' maintainers suggest this git-based install,

pip install git+https://github.com/beetbox/beets.git

... should the betanin requirements file do the same? For example:

beets @ git+https://github.com/beetbox/beets.git

I am happy to fork and PR, but wanted to open this discussion first.

Thanks for making betanin so awesome, and happy new year! :)
Andrew

Mnamer

Not really an issue, but have you considered using mnamer instead of/or including filebot. Mnamer uses way fewer resources and is of this time totally free where as Filebot is a pay only app. Its also pretty accurate and extremely fast. jkwill87/mnamer is the github site

ffmpeg aac

Hello the Convert AAC plugin It works but it doesn't convert anything in Docker This function is available ffmpeg in the container?

Thank you

pip install in a virtualenv fails

Hello,

I tried to install betanin via pip inside of a virtualenv and it failed with this:

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for greenlet
  Running setup.py clean for greenlet
Failed to build gevent greenlet
ERROR: Could not build wheels for gevent, greenlet, which is required to install pyproject.toml-based projects

This with Python 3.11.4, and it seems more of a dependency issue, but I thought I'd let you know.

Cheers

Notification services not available?

Hey, sorry if I'm being dense or missing something obvious, but the notification services menu doesn't give me any service type options in the dropdown next to "add new", the dropdown next to the URI for an added service doesn't appear, and to top it off, the service info help button doesn't do anything when I click it (you can see the little black bar under the menu selection next to "add" which is an unpopulated list):

Screenshot_20220521_190128

When I run betanin as my beets user and just leave it in the console, then open the notifications settings page in betanin, I get this traceback:

Traceback (most recent call last):
  File "/home/beets/.local/lib/python3.8/site-packages/gevent/pywsgi.py", line 999, in handle_one_response
    self.run_application()
  File "/home/beets/.local/lib/python3.8/site-packages/gevent/pywsgi.py", line 945, in run_application
    self.result = self.application(self.environ, self.start_response)
  File "/home/beets/.local/lib/python3.8/site-packages/flask/app.py", line 2464, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/beets/.local/lib/python3.8/site-packages/flask_socketio/__init__.py", line 43, in __call__
    return super(_SocketIOMiddleware, self).__call__(environ,
  File "/home/beets/.local/lib/python3.8/site-packages/engineio/middleware.py", line 74, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/beets/.local/lib/python3.8/site-packages/werkzeug/middleware/proxy_fix.py", line 232, in __call__
    return self.app(environ, start_response)
  File "/home/beets/.local/lib/python3.8/site-packages/flask/app.py", line 2450, in wsgi_app
    response = self.handle_exception(e)
  File "/home/beets/.local/lib/python3.8/site-packages/flask_restplus/api.py", line 584, in error_router
    return original_handler(e)
  File "/home/beets/.local/lib/python3.8/site-packages/flask_cors/extension.py", line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/home/beets/.local/lib/python3.8/site-packages/flask/app.py", line 1867, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/beets/.local/lib/python3.8/site-packages/flask/_compat.py", line 38, in reraise
    raise value.with_traceback(tb)
  File "/home/beets/.local/lib/python3.8/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/beets/.local/lib/python3.8/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/beets/.local/lib/python3.8/site-packages/flask_restplus/api.py", line 584, in error_router
    return original_handler(e)
  File "/home/beets/.local/lib/python3.8/site-packages/flask_cors/extension.py", line 165, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/home/beets/.local/lib/python3.8/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/beets/.local/lib/python3.8/site-packages/flask/_compat.py", line 38, in reraise
    raise value.with_traceback(tb)
  File "/home/beets/.local/lib/python3.8/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/beets/.local/lib/python3.8/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/beets/.local/lib/python3.8/site-packages/flask_restplus/api.py", line 329, in wrapper
    return self.make_response(data, code, headers=headers)
  File "/home/beets/.local/lib/python3.8/site-packages/flask_restplus/api.py", line 350, in make_response
    resp = self.representations[mediatype](data, *args, **kwargs)
  File "/home/beets/.local/lib/python3.8/site-packages/flask_restplus/representations.py", line 25, in output_json
    dumped = dumps(data, **settings) + "\n"
  File "/usr/lib/python3.8/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python3.8/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type LazyTranslation is not JSON serializable
2022-05-22T20:56:29Z {'REMOTE_ADDR': '192.168.100.100', 'REMOTE_PORT': '39558', 'HTTP_HOST': 'betanin.domain.com', (hidden keys: 34)} failed with TypeError

Remember, to get betanin to install I had to substitute importlib-metadata>=4.4 instead of the importlib-metadata==3.3.0 listed in betanin's requirements. The markdown dependency doesn't work properly otherwise since it requires importlib-metadata 4.4 or above. Once I install it, betanin launches fine but now I'm getting this problem.

hello again and the idea of a lsio/beets based image

hi @montchr, @w1ldg00se, and all

thank you for the PRs regarding basing the betanin image off of lsio/beets. I think it's a cool idea but I decided not to go for it for now. the reasons being

  • I have limited time to work on betanin and other projects these days with a busy full time job
  • my worry is that basing betanin off the lsio image could lead to the betanin build just breaking randomly like it loves to do already
  • I'm trying to make things as simple and reproducible as I can by pinning deps and having control over the base image
  • also I'm keeping in mind a future where betanin doesn't just shell out to betanin for music, but shells out to whatever media management cli tool you like

so instead I updated the image to build the likes of mp3val, mp3gain, chromaprint, lots of other stuff, by doing a docker multi stage build where those extra programs are built from APKBUILDs
(if I'm still missing some extra goodies that lsio comes with, please let me know)

on top of this

  • the new image is roughly the same size as lsio at about 200MB
  • no rustc
  • PID/GID are set by default
  • the docker volumes have changed to reflect this /root -> /b (also mentioned in readme)
  • IMO keeping it like this (just mounting a HOME directory) makes it easy to add other cli tool's config files

if you have any suggestions/questions/whatever please let me know 👍

Add better hadling for selection in interactive menu (Skip,Abort, etc.) so they won't be marked as "completed"

Currently, imports where manual action was needed, and during which Beets was told to either Skip that particual album, or Abort import, are detected by UI as success:

obraz

obraz

Now I get it that it's probably based on exit code, and probably Beets doesn't dare to report Aborted import as non-zero.

IDEA: would it be possible to check at betanin level, that:

  • check if Beets printed prompt about action to be taken,
  • and if so, track the response to that
  • based on user input, communicate action taken in GUI - for clarity

In GUI this could be reported for example in brackets, what action was taken regarding that particular import. With that one could easily come back to that later, in case they wanted to take action again against that albu that was problematic, because currently such import will be displayed as "Completed".

Here's small demo on how could it look (excuse me but I didn't bother to change colors nor icon. Let's assume Abort could be in red, Skip in yellow/red, Use-as maybe tifferent hue of green etc.)

obraz

My assumption here is that it's possible to capture whenever this interactive menu is displayed, and that user always provides predictable input within possible options. Maybe more thought should be provided into what appens if user misstypes etc.

Betanin crashes immediately on import

Hello,

First off, awesome project! I'd love to get it working however I'm having a bit of an issue. Whether triggered by API or by manual import, betanin crashes immediately when a directory is added for import and can only recover by deleting the betanin.db and restarting the daemon. My beet user and betanin user are the same, and the user has permissions to write/edit the directory being imported, so I don't think it's permissions related... Is there a way to enable debug logs for betanin?

image

System details:
OS: Proxmox PVE (Ubuntu 20.04 lxc)
CPU: 4 vCPUs
RAM: 512MB (I've tried upping this to 8GB but nothing changes)

journalctl logs:

May 18 03:26:21 beets betanin[18708]: 2022-05-18 03:26:21.431 | INFO     | betanin.jobs.import_torrents:_start:108 - got new torrent
May 18 03:26:21 beets systemd[1]: betanin.service: Succeeded.
-- Subject: Unit succeeded
-- Defined-By: systemd
-- Support: http://www.ubuntu.com/support
-- 
-- The unit betanin.service has successfully entered the 'dead' state.
May 18 03:26:21 beets systemd[1]: betanin.service: Consumed 1.784s CPU time.
-- Subject: Resources consumed by unit runtime
-- Defined-By: systemd
-- Support: http://www.ubuntu.com/support
-- 
-- The unit betanin.service completed and consumed the indicated resources.

Thanks!

Add info about necessity to setup "username" and "password" within config file

I was having trouble with launching betanin the first time (both first install on amchine and first usage in my life) because I've seen in Portainer that contianer is constantly restarting itself.

I initialy thought it's about user permissions - and indeed there was such problem, but after fixing it container still restarted itself

2023-07-23 17:25:44.999 | ERROR    | betanin.entry.betanin:_ensure_config:69 - please provide a frontend username and password

I had to provide username and password manually, using vim into my config.toml file:

[frontend]
username = "user"
password = "pass"

I believe to have truly automated and seamless experience, either:

  • provide default user + pass for application after install - there are users like me who have it behind reverse proxy with SSO, so I don't care that much about what credentials I use here
  • allow to configure them via env variables passed, i.e. using environment section in docker-compose - either credentials or even option to disable it completely
  • provide info on github page about necessity to provide these manually in confing after first run, after config generates, otherwise web page won't display

Thanks for cool piece of software, will test it soon, I hope you will find my proposal useful for the project.

Trouble adidng "beets-alternative" / external plugins into image on build

Hi,

I wanted to incorporate a beets-alternatives plugin into Betanin image.

I already have refined config I tested with dockerized version of Beets (just Beets, not Betanin) where I basically tested a pipeline I wanted to create which involves creating a mirror of my library but in MP3 format for usage with external players, such as my phone.

So I think it makes sense for me to instead keep a separate from Betanin instance of Beets, just add necessary packages to this image, so whenever I use Betanin to digets anything form staging folder for my music:

  • I use Betanin web UI to point to new folder to integrate it with library - or use one of torrent clients' integration
  • with my current config, after Betanin sucessfuly adds new file into library, I can use something like hook plugin to call beets-alternatives' beet alt update command as post-import event, so anything new is also mirrored
  • So ideally, as end goal, anything imported via Betanin is given additional handling
  • Had I ever had a need of any non-standard action - say beet update to reflect out of band changes - I would always use interactive session from within Betanin container. This allows me to avoid 2 different containers on the system.

To achieve what I'm saying I quickly added this part to my docker-compose file to ensure plugins have necessary dependencies and to install beets-alternatives plugin:

build:
# Support for beet-alternatives plugin
 dockerfile_inline: |
   FROM sentriz/betanin:v0.5.6
   RUN pip install beautifulsoup4 requests \
     && pip install --upgrade beets>=1.6.0 beets-alternatives

However this doesn;t seem to work. I verified it also on vanilla image of Betanin and tried to perform these steps through interactive shell.

beet alt command from plugin is not recognized.

/src #  pip install --upgrade beets>=1.6.0 beets-alternatives
WARNING: The directory '/b/.cache/pip' or its parent directory is not owned or is not writable by the current user. The cache has been disabled. Check the permissions and owner of that directory. If executing pip with sudo, you should use sudo's -H flag.
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
/src # beet version
beets version 1.6.1
Python version 3.11.6
no plugins loaded
/src # beet alt
error: unknown command 'alt'

I also tried doing su betanin, and then installation and effects are the same.

/src $ pip install --upgrade beets-alternatives
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: beets-alternatives in /usr/lib/python3.11/site-packages (0.11.0)
Requirement already satisfied: beets<2.0.0,>=1.6.0 in /usr/lib/python3.11/site-packages (from beets-alternatives) (1.6.1)
Requirement already satisfied: six<2.0.0,>=1.16.0 in /usr/lib/python3.11/site-packages (from beets-alternatives) (1.16.0)
Requirement already satisfied: unidecode>=1.3.6 in /usr/lib/python3.11/site-packages (from beets<2.0.0,>=1.6.0->beets-alternatives) (1.3.7)
Requirement already satisfied: musicbrainzngs>=0.4 in /usr/lib/python3.11/site-packages (from beets<2.0.0,>=1.6.0->beets-alternatives) (0.7.1)
Requirement already satisfied: pyyaml in /usr/lib/python3.11/site-packages (from beets<2.0.0,>=1.6.0->beets-alternatives) (6.0.1)
Requirement already satisfied: mediafile>=0.12.0 in /usr/lib/python3.11/site-packages (from beets<2.0.0,>=1.6.0->beets-alternatives) (0.12.0)
Requirement already satisfied: confuse>=1.5.0 in /usr/lib/python3.11/site-packages (from beets<2.0.0,>=1.6.0->beets-alternatives) (2.0.1)
Requirement already satisfied: munkres>=1.0.0 in /usr/lib/python3.11/site-packages (from beets<2.0.0,>=1.6.0->beets-alternatives) (1.1.4)
Requirement already satisfied: jellyfish in /usr/lib/python3.11/site-packages (from beets<2.0.0,>=1.6.0->beets-alternatives) (1.0.3)
Requirement already satisfied: typing-extensions in /usr/lib/python3.11/site-packages (from beets<2.0.0,>=1.6.0->beets-alternatives) (4.9.0)
Requirement already satisfied: mutagen>=1.46 in /usr/lib/python3.11/site-packages (from mediafile>=0.12.0->beets<2.0.0,>=1.6.0->beets-alternatives) (1.47.0)
/src $ beet alt
error: unknown command 'alt'

Calling beet help on both ocasions works just fine.

/src # beet help
Usage: 
  beet COMMAND [ARGS...]
  beet help COMMAND

Options:
  --format-item=FORMAT_ITEM
                        print with custom format
  --format-album=FORMAT_ALBUM
                        print with custom format
  -l LIBRARY, --library=LIBRARY
  
  ....

So - what am I missing here and what's the best way in my use case to bundle these external dependencies with app?
I believe it must be possible, it's just that I have trouble with ownership of files there.

IDEA: Listen in path for new folder/files to consume

Although I use inetgration with torrent client via proposed scripts, way more often I need to manually drag and drop folder with my newly ripped music from CDs 😋😋😋 into path which Betanin is bound to.

I wonder if more event driven pattern based on when any new folder with files gets dropped into location is possible - either by native solutions or other hacky means.

I mean currently I just have around 50 new compilations to add, manual picker isn't really convienet for that, and drop-and-forget approach would be really convienient too.

If no plan (or capacity) for native functionality, then does anyone have idea to achieve same functionality but through other means?

Add timeout for imports which need additional input (so rest of queue won't be blocked)

Let's say there is one album that for any reason (like there is slight mismatch in MusicBrainz and detected version, and it fails % threshold) can't be imported.

I've often had such situation that I attempted import of few albums in row, went away, came back only to find out that the very first album in queue clogged queue. After intervention - confirm or abort - rest very often just imported.

Proposal: Add (configurable) timeout for import - counting from time the need for input arises.

Betanin could automatically send command such as Abort or other, or just kill import process and mark it in it's databse as failed (here I assume there wouldn't be problems with database, but since beet never really started import I think that's not an issue.)

Time interval could be additionaly fetched from config file, 0 could mean disabled, and any value over 0 could be time in seconds to wait for user input.

I don't think I understand Betanin well enought to attempt an implementation (yet), but with some clues how entire process is handled, maybe I could one day work on it.

Add ability to skip/remove item in queue

An album I downloaded and automatically imported got stuck on import:

[betanin] retrying... (there are 0 items in the queue)
[betanin] starting cli program
/transcodes/a0d0bfe5799c9fb27e388a849cd7fd8acd0cba11 (V0)
/transcodes/a0d0bfe5799c9fb27e388a849cd7fd8acd0cba11 (V0)/CD 1 - Beatmania & Beatmania IIDX
/transcodes/a0d0bfe5799c9fb27e388a849cd7fd8acd0cba11 (V0)/CD 2 - Dance Dance Revolution
/transcodes/a0d0bfe5799c9fb27e388a849cd7fd8acd0cba11 (V0)/CD 3 - Pop'n Music
/transcodes/a0d0bfe5799c9fb27e388a849cd7fd8acd0cba11 (V0)/CD 4 - Guitar Freaks Drum Mania
/transcodes/a0d0bfe5799c9fb27e388a849cd7fd8acd0cba11 (V0)/CD 5 - Another Series (188 items)

Correcting tags from:
    BEMANI BEST for the 10th anniversary
To:
    BEMANI BEST for the 10th anniversary
URL:
    https://musicbrainz.org/release/25306d2c-b51f-4858-98b8-d9c70649f527
(Similarity: 50.5%)
 (...)

I assume the import failed due to the sheer number of tracks on the album, but I'm not sure.
In any case, being able to remove the item from the queue would be nice.

Kill a task in process?

I need to kill a couple of import tasks that are in process but they start up again no matter what. How can I force it to stop trying to import and never try to import that thing again unless I tell it to?

Web UI runs into timeout on many finished imports / add backend pagination

I now have nearly 1600 finished imports (0 active) and the following performance issue appeared:
The route /api/torrents isn't very efficient so with this amount of imports it takes just over 5 seconds to finish the request. The web ui has a timeout of 5 seconds (backend.js, line 9) and thus runs into the timeout, so the web ui always just shows disconnected and shows none of the finished imports.
Increasing the timeout in backend.js makes everything working again.

So the performance of the route /api/torrents should be increased somehow. By default betanin uses pagination with 50 entries per page so maybe it's possible to only return the first 50 entries and load the next 50 entries only on demand when the user visits the next site. Also sorting after the date via code is probably slower than using plain SQL. Edit: Probably not, that's standard flask_sqlalchemy code which should already generate SQL.

And a button which deletes all finished imports would be nice (and a fast fix).

Beet Config?

Hey! Sorry, I'm new to this project so I'm not super certain. For Betanin to work, do I have to have beets.io already installed?

When I got to the Settings page in Betanin and then the Beet config page, it says the config.yaml isn't present.

Thanks!

GStreamer ReplayGain error

When using the replaygain plugin with the gstreamer backend, all imports fail with the error:

error: replaygain initialization failed: Failed to load GStreamer: python-gi not found

Installing py-gobject3 and gst-plugins-good fixes this.

Parallel import

Is there any reason why there's only a single import at a time?

I added a huge bunch of import requests and many of them need manual input. I open the console, mostly
just press [A]pply or [S]kip and would like to just go to the next import with manual input. But i need to wait for the current import to finish and for the next to detect the album and request my manual input. That means i need to wait around half a minute to 5 minutes until i can proceed with the next import, so i switch to doing something else and often forget to come back.
That's the same issue i had with a bash script that starts the beet import for every folder in my music download directory and the only reason why i installed betanin.

Couldn't it just do: hey beets needs manual intervention, so i just start the next import.
And after all imports are processed they are either successfully imported or need manual input.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.