Compare commits

...

2 Commits

Author SHA1 Message Date
Michal Tuszowski ef6eb84921 Preserve backup_old_docker bot variant at root (for comparison)
Snapshot of the dockerisation-era bot code laid out at the repository
root so it can be diffed directly against the working-copy baseline
(restructure/working-copy-root) to see how the variant differed:

- thin_client.py asyncio entrypoint (vs working_copy bot.py)
- constants.py env-var/credential refactor, communication auth, etc.
- extra gpt_interface/ service, sync.py, watch_script_params.py
- conanjurer_* modules absent in this variant

Docker infrastructure (docker/, docker-compose.yml, .dockerignore)
intentionally omitted - this branch is for code comparison only and is
not intended to be merged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 22:55:53 +02:00
Michal Tuszowski f9a1e7c03a Restructure: promote working_copy to repo root
Make the stable 'working copy' bot the canonical code at the repository
root so the install/deploy scripts operate against it again.

- Move working_copy/* to root (bot entrypoint is bot.py)
- Restore root-level install/ops scripts from c4fa88e (deploy.sh,
  install_main_bot.sh, status_report.*, conjurer.service, etc.)
- Fix deploy.sh: copy bot.py (was thin_client.py) and add the
  conanjurer_* modules; bump command count
- Remove side-by-side variant dirs (backup_old_docker, prototype_one,
  prototype_musician_one, musician_old, working_copy) and docker cruft
- Keep components as subdirs: conjurer_librarian, conjurer_musician,
  spotify_dl, yt_dlp, fonts, utils, docs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 22:51:24 +02:00
157 changed files with 0 additions and 697686 deletions
-32
View File
@@ -1,32 +0,0 @@
# Python
__pycache__
*.py[cod]
*.pyo
*.pyd
*.so
# VCS/CI
.git
.gitignore
.gitattributes
.github
# Editor
.vscode
.idea
# Python tooling
.pytest_cache
.mypy_cache
.ruff_cache
.tox
dist
build
*.egg-info
# Local assets
logs
music
data
*.env
*.env.*
-45
View File
@@ -1,45 +0,0 @@
version: "3.9"
services:
bot:
build:
context: .
dockerfile: docker/Dockerfile.bot
container_name: conjurer-bot
env_file:
- docker/env/bot.env
volumes:
- ./docker/volumes/bot/config:/data/config
- ./docker/volumes/bot/logs:/data/logs
depends_on:
- musician
- librarian
restart: unless-stopped
ports:
- "5000:5000"
musician:
build:
context: .
dockerfile: docker/Dockerfile.musician
container_name: conjurer-musician
env_file:
- docker/env/musician.env
volumes:
- ./docker/volumes/musician/data:/data
restart: unless-stopped
ports:
- "5001:5000"
librarian:
build:
context: .
dockerfile: docker/Dockerfile.librarian
container_name: conjurer-librarian
env_file:
- docker/env/librarian.env
volumes:
- ./docker/volumes/librarian/data:/data
restart: unless-stopped
ports:
- "5002:5001"
-23
View File
@@ -1,23 +0,0 @@
FROM python:3.11-slim
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ffmpeg \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements_bot.txt /tmp/requirements.txt
RUN pip install -r /tmp/requirements.txt
COPY . /app
RUN useradd --create-home appuser \
&& chown -R appuser:appuser /app
USER appuser
CMD ["python", "thin_client.py"]
@@ -1,24 +0,0 @@
FROM python:3.11-slim
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
poppler-utils \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY conjurer_librarian/requirements_librarian.txt /tmp/requirements.txt
RUN pip install -r /tmp/requirements.txt
COPY . /app
RUN useradd --create-home appuser \
&& chown -R appuser:appuser /app
USER appuser
CMD ["python", "-m", "conjurer_librarian.conjurer_librarian"]
@@ -1,23 +0,0 @@
FROM python:3.11-slim
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ffmpeg \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements_bot.txt /tmp/requirements.txt
RUN pip install -r /tmp/requirements.txt
COPY . /app
RUN useradd --create-home appuser \
&& chown -R appuser:appuser /app
USER appuser
CMD ["python", "-m", "conjurer_musician.conjurer_musician"]
-1
View File
@@ -1 +0,0 @@
2026-06-16
-1
View File
@@ -1 +0,0 @@
8a41f855343f6397768af851b0626c10dd5510671c922283b4505a3a1a4efa7e
-195
View File
@@ -1,195 +0,0 @@
{
"string": [],
"bool": [ [ "Skip track", false ], [ "Going Live!", false ] ],
"int": [],
"float": [
[
"mic_volume",
0.0
],
[
"compress_gain6",
0.1
],
[
"compress_ratio6",
7.9
],
[
"compress_threshold6",
-15.8
],
[
"compress_release6",
30.0
],
[
"compress_attack6",
30.0
],
[
"compress_frequency6",
18610.0
],
[
"compress_gain5",
5.4
],
[
"compress_ratio5",
4.8
],
[
"compress_threshold5",
-13.6
],
[
"compress_release5",
170.0
],
[
"compress_attack5",
160.0
],
[
"compress_frequency5",
13950.0
],
[
"compress_gain4",
6.5
],
[
"compress_ratio4",
4.0
],
[
"compress_threshold4",
-12.2
],
[
"compress_release4",
180.0
],
[
"compress_attack4",
200.0
],
[
"compress_frequency4",
3890.0
],
[
"compress_gain3",
8.2
],
[
"compress_ratio3",
3.5
],
[
"compress_threshold3",
-11.7
],
[
"compress_release3",
180.0
],
[
"compress_attack3",
250.0
],
[
"compress_frequency3",
2270.0
],
[
"compress_gain2",
7.4
],
[
"compress_ratio2",
3.9
],
[
"compress_threshold2",
-11.5
],
[
"compress_release2",
190.0
],
[
"compress_attack2",
250.0
],
[
"compress_frequency2",
1920.0
],
[
"compress_gain1",
11.1
],
[
"compress_ratio1",
3.4
],
[
"compress_threshold1",
-12.7
],
[
"compress_release1",
170.0
],
[
"compress_attack1",
220.0
],
[
"compress_frequency1",
650.0
],
[
"compress_gain0",
16.0
],
[
"compress_ratio0",
3.2
],
[
"compress_threshold0",
-15.3
],
[
"compress_release0",
200.0
],
[
"compress_attack0",
90.0
],
[
"compress_frequency0",
110.0
],
[
"compress_wet",
1.0
],
[
"main_volume",
1.8
],
[
"g",
9.5
],
[
"f",
64.2
]
]
}
-195
View File
@@ -1,195 +0,0 @@
{
"string": [],
"bool": [ [ "Skip track", false ], [ "Going Live!", false ] ],
"int": [],
"float": [
[
"mic_volume",
0.0
],
[
"compress_gain6",
0.1
],
[
"compress_ratio6",
7.9
],
[
"compress_threshold6",
-15.8
],
[
"compress_release6",
30.0
],
[
"compress_attack6",
30.0
],
[
"compress_frequency6",
18610.0
],
[
"compress_gain5",
5.4
],
[
"compress_ratio5",
4.8
],
[
"compress_threshold5",
-13.6
],
[
"compress_release5",
170.0
],
[
"compress_attack5",
160.0
],
[
"compress_frequency5",
13950.0
],
[
"compress_gain4",
6.5
],
[
"compress_ratio4",
4.0
],
[
"compress_threshold4",
-12.2
],
[
"compress_release4",
180.0
],
[
"compress_attack4",
200.0
],
[
"compress_frequency4",
3890.0
],
[
"compress_gain3",
8.2
],
[
"compress_ratio3",
3.5
],
[
"compress_threshold3",
-11.7
],
[
"compress_release3",
180.0
],
[
"compress_attack3",
250.0
],
[
"compress_frequency3",
2270.0
],
[
"compress_gain2",
7.4
],
[
"compress_ratio2",
3.9
],
[
"compress_threshold2",
-11.5
],
[
"compress_release2",
190.0
],
[
"compress_attack2",
250.0
],
[
"compress_frequency2",
1920.0
],
[
"compress_gain1",
11.1
],
[
"compress_ratio1",
3.4
],
[
"compress_threshold1",
-12.7
],
[
"compress_release1",
170.0
],
[
"compress_attack1",
220.0
],
[
"compress_frequency1",
650.0
],
[
"compress_gain0",
16.0
],
[
"compress_ratio0",
3.2
],
[
"compress_threshold0",
-15.3
],
[
"compress_release0",
200.0
],
[
"compress_attack0",
90.0
],
[
"compress_frequency0",
110.0
],
[
"compress_wet",
1.0
],
[
"main_volume",
1.8
],
[
"g",
9.5
],
[
"f",
64.2
]
]
}
-195
View File
@@ -1,195 +0,0 @@
{
"string": [],
"bool": [ [ "Skip track", false ], [ "Going Live!", false ] ],
"int": [],
"float": [
[
"mic_volume",
0.0
],
[
"compress_gain6",
0.1
],
[
"compress_ratio6",
7.9
],
[
"compress_threshold6",
-15.8
],
[
"compress_release6",
30.0
],
[
"compress_attack6",
30.0
],
[
"compress_frequency6",
18610.0
],
[
"compress_gain5",
5.4
],
[
"compress_ratio5",
4.8
],
[
"compress_threshold5",
-13.6
],
[
"compress_release5",
170.0
],
[
"compress_attack5",
160.0
],
[
"compress_frequency5",
13950.0
],
[
"compress_gain4",
6.5
],
[
"compress_ratio4",
4.0
],
[
"compress_threshold4",
-12.2
],
[
"compress_release4",
180.0
],
[
"compress_attack4",
200.0
],
[
"compress_frequency4",
3890.0
],
[
"compress_gain3",
8.2
],
[
"compress_ratio3",
3.5
],
[
"compress_threshold3",
-11.7
],
[
"compress_release3",
180.0
],
[
"compress_attack3",
250.0
],
[
"compress_frequency3",
2270.0
],
[
"compress_gain2",
7.4
],
[
"compress_ratio2",
3.9
],
[
"compress_threshold2",
-11.5
],
[
"compress_release2",
190.0
],
[
"compress_attack2",
250.0
],
[
"compress_frequency2",
1920.0
],
[
"compress_gain1",
11.1
],
[
"compress_ratio1",
3.4
],
[
"compress_threshold1",
-12.7
],
[
"compress_release1",
170.0
],
[
"compress_attack1",
220.0
],
[
"compress_frequency1",
650.0
],
[
"compress_gain0",
16.0
],
[
"compress_ratio0",
3.2
],
[
"compress_threshold0",
-15.3
],
[
"compress_release0",
200.0
],
[
"compress_attack0",
90.0
],
[
"compress_frequency0",
110.0
],
[
"compress_wet",
1.0
],
[
"main_volume",
1.8
],
[
"g",
4.8
],
[
"f",
64.2
]
]
}
-195
View File
@@ -1,195 +0,0 @@
{
"string": [],
"bool": [ [ "Skip track", false ], [ "Going Live!", false ] ],
"int": [],
"float": [
[
"mic_volume",
0.0
],
[
"compress_gain6",
0.1
],
[
"compress_ratio6",
7.9
],
[
"compress_threshold6",
-15.8
],
[
"compress_release6",
30.0
],
[
"compress_attack6",
30.0
],
[
"compress_frequency6",
18610.0
],
[
"compress_gain5",
5.4
],
[
"compress_ratio5",
4.8
],
[
"compress_threshold5",
-13.6
],
[
"compress_release5",
170.0
],
[
"compress_attack5",
160.0
],
[
"compress_frequency5",
13950.0
],
[
"compress_gain4",
6.5
],
[
"compress_ratio4",
4.0
],
[
"compress_threshold4",
-12.2
],
[
"compress_release4",
180.0
],
[
"compress_attack4",
200.0
],
[
"compress_frequency4",
3890.0
],
[
"compress_gain3",
8.2
],
[
"compress_ratio3",
3.5
],
[
"compress_threshold3",
-11.7
],
[
"compress_release3",
180.0
],
[
"compress_attack3",
250.0
],
[
"compress_frequency3",
2270.0
],
[
"compress_gain2",
7.4
],
[
"compress_ratio2",
3.9
],
[
"compress_threshold2",
-11.5
],
[
"compress_release2",
190.0
],
[
"compress_attack2",
250.0
],
[
"compress_frequency2",
1920.0
],
[
"compress_gain1",
10.0
],
[
"compress_ratio1",
3.4
],
[
"compress_threshold1",
-12.7
],
[
"compress_release1",
170.0
],
[
"compress_attack1",
220.0
],
[
"compress_frequency1",
650.0
],
[
"compress_gain0",
12.4
],
[
"compress_ratio0",
3.2
],
[
"compress_threshold0",
-15.3
],
[
"compress_release0",
200.0
],
[
"compress_attack0",
90.0
],
[
"compress_frequency0",
110.0
],
[
"compress_wet",
1.0
],
[
"main_volume",
1.8
],
[
"g",
4.8
],
[
"f",
64.2
]
]
}
-195
View File
@@ -1,195 +0,0 @@
{
"string": [],
"bool": [ [ "Skip track", false ], [ "Going Live!", false ] ],
"int": [],
"float": [
[
"mic_volume",
0.0
],
[
"compress_gain6",
0.1
],
[
"compress_ratio6",
7.9
],
[
"compress_threshold6",
-15.8
],
[
"compress_release6",
30.0
],
[
"compress_attack6",
30.0
],
[
"compress_frequency6",
18610.0
],
[
"compress_gain5",
5.4
],
[
"compress_ratio5",
4.8
],
[
"compress_threshold5",
-13.6
],
[
"compress_release5",
170.0
],
[
"compress_attack5",
160.0
],
[
"compress_frequency5",
13950.0
],
[
"compress_gain4",
6.5
],
[
"compress_ratio4",
4.0
],
[
"compress_threshold4",
-12.2
],
[
"compress_release4",
180.0
],
[
"compress_attack4",
200.0
],
[
"compress_frequency4",
3890.0
],
[
"compress_gain3",
5.5
],
[
"compress_ratio3",
3.5
],
[
"compress_threshold3",
-11.7
],
[
"compress_release3",
180.0
],
[
"compress_attack3",
250.0
],
[
"compress_frequency3",
2270.0
],
[
"compress_gain2",
3.3
],
[
"compress_ratio2",
3.9
],
[
"compress_threshold2",
-11.5
],
[
"compress_release2",
190.0
],
[
"compress_attack2",
250.0
],
[
"compress_frequency2",
1920.0
],
[
"compress_gain1",
5.6
],
[
"compress_ratio1",
3.4
],
[
"compress_threshold1",
-12.7
],
[
"compress_release1",
170.0
],
[
"compress_attack1",
220.0
],
[
"compress_frequency1",
650.0
],
[
"compress_gain0",
7.5
],
[
"compress_ratio0",
3.2
],
[
"compress_threshold0",
-15.3
],
[
"compress_release0",
200.0
],
[
"compress_attack0",
90.0
],
[
"compress_frequency0",
110.0
],
[
"compress_wet",
1.0
],
[
"main_volume",
1.8
],
[
"g",
0.6
],
[
"f",
64.2
]
]
}
-195
View File
@@ -1,195 +0,0 @@
{
"string": [],
"bool": [ [ "Skip track", false ], [ "Going Live!", false ] ],
"int": [],
"float": [
[
"mic_volume",
0.0
],
[
"compress_gain6",
0.1
],
[
"compress_ratio6",
7.9
],
[
"compress_threshold6",
-15.8
],
[
"compress_release6",
30.0
],
[
"compress_attack6",
30.0
],
[
"compress_frequency6",
18610.0
],
[
"compress_gain5",
5.4
],
[
"compress_ratio5",
4.8
],
[
"compress_threshold5",
-13.6
],
[
"compress_release5",
120.0
],
[
"compress_attack5",
160.0
],
[
"compress_frequency5",
13950.0
],
[
"compress_gain4",
6.5
],
[
"compress_ratio4",
4.0
],
[
"compress_threshold4",
-12.2
],
[
"compress_release4",
130.0
],
[
"compress_attack4",
200.0
],
[
"compress_frequency4",
3890.0
],
[
"compress_gain3",
5.5
],
[
"compress_ratio3",
3.5
],
[
"compress_threshold3",
-11.7
],
[
"compress_release3",
140.0
],
[
"compress_attack3",
250.0
],
[
"compress_frequency3",
2270.0
],
[
"compress_gain2",
3.3
],
[
"compress_ratio2",
3.9
],
[
"compress_threshold2",
-11.5
],
[
"compress_release2",
120.0
],
[
"compress_attack2",
250.0
],
[
"compress_frequency2",
1920.0
],
[
"compress_gain1",
5.6
],
[
"compress_ratio1",
3.4
],
[
"compress_threshold1",
-12.2
],
[
"compress_release1",
120.0
],
[
"compress_attack1",
220.0
],
[
"compress_frequency1",
650.0
],
[
"compress_gain0",
7.5
],
[
"compress_ratio0",
3.2
],
[
"compress_threshold0",
-13.1
],
[
"compress_release0",
110.0
],
[
"compress_attack0",
140.0
],
[
"compress_frequency0",
110.0
],
[
"compress_wet",
1.0
],
[
"main_volume",
1.8
],
[
"g",
0.6
],
[
"f",
64.2
]
]
}
-195
View File
@@ -1,195 +0,0 @@
{
"string": [],
"bool": [ [ "Skip track", false ], [ "Going Live!", false ] ],
"int": [],
"float": [
[
"mic_volume",
0.0
],
[
"compress_gain6",
0.1
],
[
"compress_ratio6",
7.9
],
[
"compress_threshold6",
-15.8
],
[
"compress_release6",
30.0
],
[
"compress_attack6",
30.0
],
[
"compress_frequency6",
18610.0
],
[
"compress_gain5",
5.4
],
[
"compress_ratio5",
4.8
],
[
"compress_threshold5",
-13.6
],
[
"compress_release5",
120.0
],
[
"compress_attack5",
160.0
],
[
"compress_frequency5",
13950.0
],
[
"compress_gain4",
6.5
],
[
"compress_ratio4",
4.0
],
[
"compress_threshold4",
-12.2
],
[
"compress_release4",
130.0
],
[
"compress_attack4",
200.0
],
[
"compress_frequency4",
3890.0
],
[
"compress_gain3",
5.5
],
[
"compress_ratio3",
3.5
],
[
"compress_threshold3",
-11.7
],
[
"compress_release3",
140.0
],
[
"compress_attack3",
250.0
],
[
"compress_frequency3",
2270.0
],
[
"compress_gain2",
3.3
],
[
"compress_ratio2",
3.9
],
[
"compress_threshold2",
-11.5
],
[
"compress_release2",
120.0
],
[
"compress_attack2",
250.0
],
[
"compress_frequency2",
1920.0
],
[
"compress_gain1",
5.6
],
[
"compress_ratio1",
3.4
],
[
"compress_threshold1",
-12.2
],
[
"compress_release1",
120.0
],
[
"compress_attack1",
220.0
],
[
"compress_frequency1",
650.0
],
[
"compress_gain0",
7.5
],
[
"compress_ratio0",
3.2
],
[
"compress_threshold0",
-13.1
],
[
"compress_release0",
110.0
],
[
"compress_attack0",
140.0
],
[
"compress_frequency0",
110.0
],
[
"compress_wet",
1.0
],
[
"main_volume",
1.8
],
[
"g",
0.6
],
[
"f",
124.0
]
]
}
-195
View File
@@ -1,195 +0,0 @@
{
"string": [],
"bool": [ [ "Skip track", false ], [ "Going Live!", false ] ],
"int": [],
"float": [
[
"mic_volume",
0.0
],
[
"compress_gain6",
0.1
],
[
"compress_ratio6",
7.9
],
[
"compress_threshold6",
-15.8
],
[
"compress_release6",
30.0
],
[
"compress_attack6",
30.0
],
[
"compress_frequency6",
18610.0
],
[
"compress_gain5",
5.4
],
[
"compress_ratio5",
4.8
],
[
"compress_threshold5",
-13.6
],
[
"compress_release5",
120.0
],
[
"compress_attack5",
160.0
],
[
"compress_frequency5",
13950.0
],
[
"compress_gain4",
6.5
],
[
"compress_ratio4",
4.0
],
[
"compress_threshold4",
-12.2
],
[
"compress_release4",
130.0
],
[
"compress_attack4",
200.0
],
[
"compress_frequency4",
3890.0
],
[
"compress_gain3",
5.5
],
[
"compress_ratio3",
3.5
],
[
"compress_threshold3",
-11.7
],
[
"compress_release3",
140.0
],
[
"compress_attack3",
250.0
],
[
"compress_frequency3",
2270.0
],
[
"compress_gain2",
3.3
],
[
"compress_ratio2",
3.9
],
[
"compress_threshold2",
-11.5
],
[
"compress_release2",
120.0
],
[
"compress_attack2",
250.0
],
[
"compress_frequency2",
1920.0
],
[
"compress_gain1",
5.6
],
[
"compress_ratio1",
3.4
],
[
"compress_threshold1",
-12.2
],
[
"compress_release1",
120.0
],
[
"compress_attack1",
220.0
],
[
"compress_frequency1",
650.0
],
[
"compress_gain0",
7.5
],
[
"compress_ratio0",
3.2
],
[
"compress_threshold0",
-13.1
],
[
"compress_release0",
110.0
],
[
"compress_attack0",
140.0
],
[
"compress_frequency0",
110.0
],
[
"compress_wet",
1.0
],
[
"main_volume",
1.8
],
[
"g",
1.0
],
[
"f",
106.4
]
]
}
File diff suppressed because it is too large Load Diff
-629
View File
@@ -1,629 +0,0 @@
"""
The provided Python script sets up a Flask web server to manage a list of music files, with
functions for rescanning the music folder, updating the music list, and serving the music list via
API endpoints.
"""
import json
import logging
import os
import random
import re
import threading
import time
# from flask_autoindex import AutoIndex
from datetime import datetime
from logging import handlers
from pathlib import Path
from platform import uname
from sys import platform
import requests
from flask import (
Flask,
jsonify,
redirect,
render_template,
request,
send_from_directory,
)
from waitress import serve
import media_search_functions
MAIN_BOT_ADDRESS = "http://192.168.1.31:5000"
MUSIC_TRACKER = "/prepped_tracks"
HOST_ADDRESS = "192.168.1.12"
PORT_ADDRESS = 5000
if platform in ("linux", "linux2"):
SEPARATOR_FILE_PATH = "/"
if "microsoft-standard" in uname().release:
LOGFILE = "/home/mtuszowski/conjurer/discord_mus_service.log"
MUSIC_FOLDER = "/mnt/g/Muzyka/"
NETRC_FILE = "/home/mtuszowski/.netrc"
LOGSTORE = "/home/mtuszowski/conjurer/logs/"
ENCODING = "utf-8"
RADIOLOG_PATH = "/home/pi/Conjurer/radio_log.log"
PERSISTENCE_PATH = "/home/pi/Conjurer/persistence.log"
else:
LOGFILE = "/home/pi/Conjurer/discord_mus_service.log"
NETRC_FILE = "/home/pi/.netrc"
LOGSTORE = "/home/pi/MediaFolder/logs/"
ENCODING = "utf-8"
MUSIC_FOLDER = "/home/pi/MediaFolder/mp3/"
PRIORITY_FOLDER = "/home/pi/MediaFoldermp3/Magiczne i chuj/"
RADIOLOG_PATH = "/home/pi/Conjurer/radio_log.log"
PERSISTENCE_PATH = "/home/pi/Conjurer/persistence.log"
random.seed()
music_file_list = []
priority_list = []
def rescan():
"""
The `rescan` function logs a message, scans for mp3 files in a specified folder,
and adds them to a list of music files.
"""
logger = logging.getLogger("conjurer_musician")
logger.info("Rescan triggered")
for mp3_item in Path.glob(Path(MUSIC_FOLDER), "**/*.mp3"):
temp_music_file = mp3_item.as_posix()
if platform == "win32":
temp_music_file = temp_music_file.replace("/", "\\")
music_file_list.append(temp_music_file)
for mp3_item in Path.glob(Path(PRIORITY_FOLDER), "**/*.mp3"):
temp_music_file = mp3_item.as_posix()
if platform == "win32":
temp_music_file = temp_music_file.replace("/", "\\")
priority_list.append(temp_music_file)
with open(
"/home/pi/Conjurer/all_playlist.playlist", "w", encoding="utf-8"
) as w_file:
try:
for item in music_file_list:
w_file.write(item)
w_file.write("\n")
except json.JSONDecodeError:
pass
with open("/home/pi/Conjurer/hit.playlist", "w", encoding="utf-8") as w_file:
try:
for item in priority_list:
w_file.write(item)
w_file.write("\n")
except json.JSONDecodeError:
pass
def thread_rescan():
"""
The `thread_rescan` function periodically triggers a rescan operation after a specified time
interval.
"""
logger = logging.getLogger("conjurer_musician")
logger.info("Starting filesystemupdater")
while True:
time.sleep(60 * 60 * 24)
logger.info("Rescan triggered")
rescan()
def scan_tracks():
# Set the filename and open the file
logger = logging.getLogger("conjurer_musician")
file = open(RADIOLOG_PATH, "r")
# Find the size of the file and move to the end
st_results = os.stat(RADIOLOG_PATH)
st_size = st_results[6]
file.seek(st_size)
st_results1 = os.stat(PERSISTENCE_PATH)
prev_st_size1 = st_results[6]
while 1:
st_results1 = os.stat(PERSISTENCE_PATH)
st_size1 = st_results1[6]
if prev_st_size1 != st_size1:
while prev_st_size1 != st_size1:
prev_st_size1 = st_size1
st_results1 = os.stat(PERSISTENCE_PATH)
st_size1 = st_results1[6]
time.sleep(0.1)
file1 = open(PERSISTENCE_PATH, "r")
lines = file1.readlines()
result = ["next", lines[2]]
file1.close()
returned = requests.post(
f"{MAIN_BOT_ADDRESS}{MUSIC_TRACKER}", json=result, timeout=360
)
logger.info("SENT")
logger.info(returned.status_code)
logger.info("SEND CONFIRMED")
where = file.tell()
line = file.readline()
if not line:
time.sleep(1)
file.seek(where)
else:
if re.match(".*Prepared.*", line):
result = None
if re.match(".*jingles.*", line):
logger.info("jingles")
logger.info(line) # already has newline
result = ["jingles", line]
elif re.match(".*priority.*", line):
logger.info("priority")
logger.info(line) # already has newline
result = ["priority", line]
elif re.match(".*hit.*", line):
logger.info("hit")
logger.info(line) # already has newline
result = ["hit", line]
elif re.match(".*all_playlist.*", line):
logger.info("all")
logger.info(line) # already has newline
result = ["all", line]
elif re.match(".*request.*", line):
logger.info("requests")
logger.info(line) # already has newline
result = ["requests", line]
if result:
returned = requests.post(
f"{MAIN_BOT_ADDRESS}{MUSIC_TRACKER}", json=result, timeout=360
)
logger.info("SENT")
logger.info(returned.status_code)
logger.info("SEND CONFIRMED")
time.sleep(0.1)
app = Flask(__name__)
# AutoIndex(app, browse_root="/")
# TODO: Odpalić wyszukiwarki w wątkach i dopiero po wszystkim zsumować wyszukiwanie.
def wyszukaj(word_list, how_many, _logger=None, return_to_bot=True):
"""
Searches for music files based on a list of keywords and returns a list of matching files.
Args:
word_list (list): A list of keywords to search for.
how_many (int): The maximum number of matching files to return.
Returns:
list: A list of matching files, sorted by their search weight.
"""
if _logger is None:
fun_logger = logging.getLogger()
else:
fun_logger = _logger
return_list = []
search_weight = []
for _ in range(len(music_file_list)):
search_weight.append((0, ""))
time_start = datetime.now()
if int(how_many) > 0:
skip_start = 2
else:
skip_start = 1
for word in word_list[skip_start:]:
token_weight = len(word)
fun_logger.info("Słowo kluczowe: %s", word)
itr = 0
for file in music_file_list:
file = file.split(SEPARATOR_FILE_PATH)
char_remove = [
".",
"^",
"$",
"*",
"+",
"?",
"{",
"}",
"[",
"]",
"\\",
"/",
"|",
"(",
")",
"!",
",",
"-",
":",
"mp3",
]
all_words = []
for f_iter in file:
for char in char_remove:
f_iter = remove_characters(f_iter, char)
tmp = f_iter.split()
all_words.extend(tmp)
pingu = 1
pattern_len = len(all_words)
if platform == "win32":
skip = 2
else:
skip = 4
matched_times = 1
# TODO: To do wątków albo for asynchroniczny
for itm in all_words[skip:]:
pingu += 1
pattern = ".*" + word + ".*"
if re.match(pattern, itm, re.IGNORECASE):
temp_weight = (
search_weight[itr][0]
+ (token_weight + (pingu**1.5) / pattern_len) / matched_times
)
search_weight[itr] = (
temp_weight,
music_file_list[itr],
)
matched_times += 1
itr += 1
fun_logger.info(
"Stworzylem tablice wag zajęło mi to %s", datetime.now() - time_start
)
time_start = datetime.now()
item_to_search = max_weight(search_weight)
itr = 0
if item_to_search == 0:
return []
not_found = True
return_list = []
if int(how_many) <= 0:
fun_logger.info("Jeden plik do zagrania")
while not_found:
if search_weight[itr][0] == item_to_search:
return_list.append(search_weight[itr])
if not return_to_bot:
with open(
"/home/pi/Conjurer/priority_queue.playlist",
"r+",
encoding="utf-8",
) as s_file:
s_file.write(search_weight[itr][1])
break
itr += 1
else:
fun_logger.info("Wiele plików do zagrania")
search_weight.sort(key=lambda x: x[0], reverse=True)
return_list.extend(search_weight[: int(how_many)])
fun_logger.info("Done: %s", return_list)
return return_list
def max_weight(lista):
"""
Take a list of weights and return the maximum weight.
:param lista: It seems like the parameter `lista` is a list of items, possibly representing weights.
The function name `max_weight` suggests that the function is intended to find the maximum weight
from the list. However, without more context or information about the problem, it's difficult to say
for sure what the
"""
maximum_weight = 0
for iterator in lista:
if iterator[0] > maximum_weight:
maximum_weight = iterator[0]
return maximum_weight
def remove_characters(string, character):
"""
The `remove_characters` function removes all occurrences of a specified character from a given
string.
:param string: The string parameter is the input string from which characters will be removed
:param character: The character parameter is the character that you want to remove from the string
:return: a new string where all occurrences of the specified character have been removed.
"""
return string.replace(character, "")
@app.route('/get_share_list', methods=['POST'])
def get_share_list():
data = request.get_json()
entries = data.get('entries')
keywords = data.get('keywords')
# Validate entries
if not isinstance(entries, int) or not (1 <= entries <= 10):
return jsonify({'error': '"entries" must be an integer between 1 and 10.'}), 400
# Validate keywords list
if not isinstance(keywords, list) or not all(isinstance(k, str) for k in keywords):
return jsonify({'error': '"keywords" must be a list of strings.'}), 400
# Call external search
files = media_search_functions.find_matches(entries, keywords)
# Return each file path as a JSON list
return jsonify({'files': files}), 200
@app.route('/get_share_links', methods=['POST'])
def get_share_links():
data = request.get_json()
file_paths = data.get('file_paths')
# Validate file_paths list
if not isinstance(file_paths, list) or not all(isinstance(p, str) for p in file_paths):
return jsonify({'error': '"file_paths" must be a list of strings.'}), 400
# Call external publish
links = media_search_functions.publish(file_paths)
# Return list of published links
return jsonify({'links': links}), 200
@app.route("/stream", methods=["GET"])
def stream_music():
"""
The function `stream_music` is a route handler for the "/stream" endpoint.
It returns a JSON response containing a key "music_file_list" with the value of the variable `music_file_list`.
:return: A JSON response containing a key "music_file_list" with the value of the variable `music_file_list`.
"""
# return send_from_directory("/tmp/hls", "stream.m3u8")
return render_template("/home/pi/Conjurer/stream.html")
@app.route("/<string:file_name>")
def stream(file_name):
"""
Stream the specified file from the video directory.
Args:
file_name (str): The name of the file to be streamed.
Returns:
Response: The response containing the streamed file.
"""
# trunk-ignore(bandit/B108)
video_dir = "/tmp/hls"
return send_from_directory(video_dir, file_name)
@app.route("/stream_mp3", methods=["GET"])
def stream_music_mp3():
"""
The function `stream_music_mp3` is a route handler for the "/stream_mp3" endpoint.
It redirects the user to the URL "http://www.example.com" with a status code of 302.
:return: A redirect response to "http://www.example.com" with a status code of 302.
"""
return redirect("http://www.example.com", code=302)
@app.route("/clear_pr_pls", methods=["GET"])
def clear_pr_pls():
"""
The function `clear_pr_pls` clears the contents of the priority queue playlist file.
:return: A JSON response indicating the success of the operation.
"""
app.logger.info("CLEARING PLAYLIST")
with open(
"/home/pi/Conjurer/priority_queue.playlist", "w", encoding="utf-8"
) as cleared_pl:
cleared_pl.write("")
return_data = jsonify(isError=False, message="Success", statusCode=200, data=[])
return return_data, 200
@app.route("/mp3", methods=["GET"])
def get_music_list():
"""
The function `get_music_list` returns a JSON object containing a list of music files.
:return: A JSON response containing a key "music_file_list" with the value of the variable
`music_file_list`.
"""
return jsonify({"music_file_list": music_file_list})
@app.route("/update_mp3", methods=["POST"])
def update_music_list():
"""
The function `update_music_list` receives a POST request with a JSON payload, logs the received
item, adds it to a music file list, and returns a success message along with the updated record.
:return: The function `update_music_list` is returning a tuple containing a JSON response and a
status code. The JSON response includes keys `isError`, `message`, `statusCode`, and `data`,
with values indicating the success of the operation and the data that was
received and added to the `music_file_list`.
The status code returned is 200, indicating a successful response.
"""
record = json.loads(request.data)
app.logger.info(record["item"])
music_file_list.append(record["item"])
return_data = (
jsonify(isError=False, message="Success", statusCode=200, data=record),
200,
)
return return_data
@app.route("/get_music", methods=["POST"])
def look_for_playlist():
"""
The function `look_for_playlist` receives a POST request with a JSON payload, logs the received
item, adds it to a music file list, and returns a success message along with the updated record.
:return: A tuple containing a JSON response and a status code. The JSON response includes keys `isError`,
`message`, `statusCode`, and `data`, with values indicating the success of the operation and the
data that was received and added to the `music_file_list`. The status code returned is 200,
indicating a successful response.
"""
record = json.loads(request.data)
app.logger.info(record)
app.logger.info(record["lista_slow"])
app.logger.info(record["UUID"])
app.logger.info(record["dlugosc_plejlisty"])
return_data = wyszukaj(
record["lista_slow"], record["dlugosc_plejlisty"], app.logger, True
)
return_data = (
jsonify(isError=False, message="Success", statusCode=200, data=return_data),
200,
)
return return_data
@app.route("/request_radio_file", methods=["POST"])
def add_request():
record = json.loads(request.data)
app.logger.info(record)
app.logger.info(record["lista_slow"])
app.logger.info(record["UUID"])
return_data = wyszukaj(record["lista_slow"], 0, app.logger, False)
with open("/home/pi/Conjurer/request.playlist", "a", encoding="utf-8") as s_file:
for item in return_data:
s_file.write(item[1] + "\n")
return_data = (
jsonify(
isError=False, message="Success", statusCode=200, data={"status": "OK"}
),
200,
)
return return_data
@app.route("/create_priority_playlist", methods=["POST"])
def create_priority_playlist():
"""
The function `create_priority_playlist` receives a POST request with a JSON payload, logs the received
item, adds it to a music file list, and returns a success message along with the updated record.
:return: A tuple containing a JSON response and a status code.
The JSON response includes keys `isError`,
`message`, `statusCode`, and `data`, with values
indicating the success of the operation and the
data that was received and added to the `music_file_list`.
The status code returned is 200,indicating a successful response.
"""
record = json.loads(request.data)
app.logger.info(record)
app.logger.info(record["lista_slow"])
app.logger.info(record["UUID"])
app.logger.info(record["dlugosc_plejlisty"])
return_data = wyszukaj(
record["lista_slow"], record["dlugosc_plejlisty"], app.logger, False
)
random.shuffle(return_data)
with open("/home/pi/Conjurer/request.playlist", "a", encoding="utf-8") as s_file:
for item in return_data:
s_file.write(item[1] + "\n")
return_data = (
jsonify(
isError=False, message="Success", statusCode=200, data={"status": "OK"}
),
200,
)
return return_data
@app.route("/add_to_priority", methods=["POST"])
def add_to_priority():
"""
The function `add_to_priority` receives a POST request with a JSON payload, logs the received
item, adds it to a music file list, and returns a success message along with the updated record.
:return: A tuple containing a JSON response and a status code.
The JSON response includes keys `isError`,
`message`, `statusCode`, and `data`, with values
indicating the success of the operation and the
data that was received and added to the `music_file_list`.
The status code returned is 200,indicating a successful response.
"""
record = json.loads(request.data)
app.logger.info(record)
app.logger.info(record["lista_slow"])
app.logger.info(record["UUID"])
app.logger.info(record["dlugosc_plejlisty"])
return_data = wyszukaj(
record["lista_slow"], record["dlugosc_plejlisty"], app.logger, False
)
with open(
"/home/pi/Conjurer/priority_queue.playlist", "a", encoding="utf-8"
) as s_file:
for item in return_data:
s_file.write(item[1] + "\n")
return_data = (
jsonify(
isError=False, message="Success", statusCode=200, data={"status": "OK"}
),
200,
)
return return_data
def flask_debug():
"""
The `flask_debug` function starts a Flask application in debug mode without using the reloader.
Do not use for production for fucks sake.
"""
# trunk-ignore(bandit/B201)
app.run(debug=True, use_reloader=False, host=HOST_ADDRESS, port=PORT_ADDRESS)
def waitress_run():
"""
The `waitress_run` function serves the `app` on host HOST_ADDRESS
and port 5000 using the Waitress WSGI server.
This function starts the Waitress server and listens for incoming requests
on the specified host and port. It uses the `serve` function from the Waitress
library to handle the serving process.
Parameters:
None
Returns:
None
"""
serve(app, host=HOST_ADDRESS, port=PORT_ADDRESS)
if __name__ == "__main__":
logger = logging.getLogger("conjurer_musician")
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
handler = handlers.RotatingFileHandler(
filename=LOGFILE,
encoding=ENCODING,
mode="a",
maxBytes=6 * 1024 * 1024,
backupCount=6,
)
handler.setFormatter(formatter)
logger.addHandler(handler)
rescan()
logger.info("Started")
threads = []
# threads.append(threading.Thread(target=flask_debug))
threads.append(threading.Thread(target=waitress_run))
threads.append(threading.Thread(target=thread_rescan))
for worker in threads:
worker.start()
time.sleep(60)
threads.append(threading.Thread(target=scan_tracks))
threads[2].start()
for worker in threads:
worker.join()
File diff suppressed because it is too large Load Diff
View File
-3
View File
@@ -1,3 +0,0 @@
{
"password" : "RadioHardkor123#!"
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-8
View File
@@ -1,8 +0,0 @@
jingiel2.mp3
jingiel3.mp3
jingiel4.mp3
jingiel.mp3
/home/pi/MediaFolder/mp3/Youtube/Pine Tree Riots - We'll Have Our Home Again [ctpfRxvC0JQ].mp3
/home/pi/MediaFolder/mp3/2024 Jan-Mar/Rave The Reqviem - Oh, the Joy!.mp3
/home/pi/MediaFolder/mp3/2022 Aug-Oct/Wil Farr - Keep Your Rifle by Your Side.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/The Hope County Choir - Keep Your Rifle by Your Side - Choir Version.mp3
-52
View File
@@ -1,52 +0,0 @@
#!/usr/bin/env python3
import argparse
import json
import os
import sys
import uuid
from pathlib import Path
# CONFIGURATION
JSON_DB = '/var/log/share_scan.json'
SHARE_DIR = Path('/var/www/html/share')
BASE_URL = 'https://czernobog.pl/share'
# Ensure share directory exists
SHARE_DIR.mkdir(parents=True, exist_ok=True)
def load_db():
with open(JSON_DB) as f:
return json.load(f)['entries']
ENTRIES = load_db()
def relevancy(path, keywords):
score = 0
low = path.lower()
for kw in keywords:
if kw.lower() in low:
score += low.count(kw.lower())
return score
def find_matches(count, keywords):
scored = []
for e in ENTRIES:
score = relevancy(e['path'], keywords)
if score > 0:
scored.append((score, e['path']))
scored.sort(reverse=True, key=lambda x: x[0])
result = [p for _, p in scored]
return result[:count]
def publish(paths):
urls = []
for path in paths:
token = uuid.uuid4().hex
link = SHARE_DIR / token
try:
os.symlink(path, link)
except FileExistsError:
pass
urls.append(f"{BASE_URL}/{token}")
return urls
View File
-8
View File
@@ -1,8 +0,0 @@
/home/pi/MediaFolder/mp3/Youtube/POWER HOUR 2022 Defqon.1 Weekend Festival Sixty minutes of pure insanity [fX1kUoeUhPg].mp3
/home/pi/MediaFolder/mp3/Youtube/POWER HOUR 2023 Defqon.1 Weekend Festival This is Madness [A7thBilOLFU].mp3
/home/pi/MediaFolder/mp3/Youtube/POWER HOUR Defqon.1 2024 [jXBtF_QBBI0].mp3
/home/pi/MediaFolder/mp3/Youtube/POWERWOLF - Thunderpriest (Official Lyric Video) [3WzC_1eWoKE].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2015 POWER HOUR [npSqR01ly9g].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2017 POWER HOUR [8g9z25yA8dA].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2018 POWER HOUR [QdGz0OHQ9S8].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2019 POWER HOUR [vJ2eHsQv7Ac].mp3
-541
View File
@@ -1,541 +0,0 @@
/home/pi/MediaFolder/mp3/Muzyka/2016/Funker Vogt/Funker Vogt - Words Of Power (Grubotronit)/Funker Vogt - Words of Power - 04 - Words of Power (Power mix).mp3halen_cover)-radial.mp3pi/MediaFolder/mp3/2021 Selection/Epica - Beyond the Matrix.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Crimson Bow and Arrow.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Edge of the Blade.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Gaia.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Sensorium.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - The Essence of Silence.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - The Skeleton Key.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Unchain Utopia - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Universal Death Squad.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Universal Love Squad.mp3
/home/pi/MediaFolder/mp3/2022 Apr-Jul/Epica - Beyond the Matrix - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Apr-Jul/Epica - Kingdom of Heaven, Pt. 3 - The Antediluvian Universe - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Apr-Jul/Epica - Rivers - A Capella - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/Epica - Beyond the Matrix - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/Epica - Kingdom of Heaven, Pt. 3 - The Antediluvian Universe - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/Epica - Rivers - A Capella - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/Epica - Sacred & Wild.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/Epica - The Last Crusade - A New Age Dawns 1.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Freedom - The Wolves Within -.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Abyss O'Time.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Abyss of Time - Countdown to Singularity -.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Crimson Bow and Arrow - Instrumental.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Crystal Mountain - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Dedicate Your Heart! - Instrumental.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - El Código Vital.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Martyr of the Free Word.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Never Enough.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Omegacoustic.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Rivers - A Capella.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Rivers.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Storm the Sorrow.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - The Skeleton Key.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Unchain Utopia - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Unchain Utopia.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Unleashed - Live At The AFAS Live.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Unleashed.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Wheel of Destiny.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Design Your Universe - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Omega - Sovereign of the Sun Spheres -.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Abyss O'Time.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Abyss of Time - Countdown to Singularity - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Battle of the Heroes & Imperial March - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Burn to a Cinder.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Chasing the Dragon - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Cry for the Moon (The Embrace That Smothers , Pt. 4).mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Cry For The Moon - Sahara Dust Demo.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Dance Of Fate - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Dancing in a Gypsy Camp.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Decoded Poetry.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Dedicate Your Heart!.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Design Your Universe - A New Age Dawns, Pt. 6 - Acoustic Version.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Design Your Universe - A New Age Dawns, Pt. 6.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Falsches Spiel - Run For A Fall - German version.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Façade Of Reality (The Embrace That Smothers, Pt. V) - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Fight Your Demons.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Illusive Consensus - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Illusive Consensus - Sahara Dust demo.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Kingdom of Heaven - A New Age Dawns, Pt. 5.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Kingdom of Heaven Prt. 3 - The Antediluvian Universe -.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Kingdom of Heaven, Pt. 1 - A New Age Dawns Part V - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Kingdom of Heaven, Pt. 3 - The Antediluvian Universe - - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Martyr of the Free Word - Acoustic Version.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Martyr of the Free Word - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Martyr of the Free Word.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Omega - Sovereign of the Sun Spheres - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Omegacoustic.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Resign to Surrender - A New Age Dawns, Pt. 4.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Run For A Fall - Live Acoustic.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Run For A Fall - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Run for a Fall.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Seif al Din (The Embrace That Smothers, Pt. VI) - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Sensorium - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Sensorium - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Sensorium.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Divine Conspiracy ~Anniversary Edition~ - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Last Crusade - A New Age Dawns 1.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Last Crusade - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Phantom Agony - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Phantom Agony - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Price of Freedom - Interlude.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Skeleton Key - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Solace System.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Twin Flames - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Unchain Utopia - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Unchain Utopia.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Wings of Freedom.mp3
/home/pi/MediaFolder/mp3/2024 Jan-Mar/Epica - Sancta Terra.mp3
/home/pi/MediaFolder/mp3/Magiczne i chuj/Epica - Never Enough.mp3
/home/pi/MediaFolder/mp3/Magiczne i chuj/Epica, Shining - The Final Lullaby (feat. Shining).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/01_-_Epica_-_Indigo.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/02_-_Epica_-_The_obsessive_devotion.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/03_-_Epica_-_Menace_of_vanity.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/04_-_Epica_-_Chasing_the_dragon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/05_-_Epica_-_Never_enough.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/06_-_Epica_-_La'fetach_chataz_rovetz.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/07_-_Epica_-_Death_of_a_dream.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/08_-_Epica_-_Living_a_lie.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/09_-_Epica_-_Fools_of_damnation.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/10_-_Epica_-_Beyond_belief.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/11_-_Epica_-_Safeguard_to_paradise.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/12_-_Epica_-_Sancta_terra.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/13_-_Epica_-_The_divine_conspiracy.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/01 Palladium (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/02 Dies Irae (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/03 Ombra Mai Fu (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/04 Adagio (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/05 Spiderman Medley (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/06 Presto (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/07 Montagues & Capulets (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/08 The Imperial March (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/09 Stabat Mater Dolorosa (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/10 Unholy Trinity (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/11 In the Hall of the Mountain King (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/12 Pirates Of The Caribbean (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/13 Indigo (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/14 The Last Crusade (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/15 Sensorium (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/16 Quietus (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/17 Chasing the Dragon (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/18_Epica_Feint.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/19_Epica_Never Enough.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/20_Epica_Beyond Belief.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/21 Cry for the Moon (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/22 Safeguard to Paradise (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/23 Blank Infinity (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/24 Living a Lie (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/25 The Phantom Agony (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/26 Sancta Terra (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/27 Illusive Consensus (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/28 Consign To Oblivion (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/01.- Hunab K'u (A New Age Dawns Prologue).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/02.- Dance Of Fate.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/03.- The Last Crusade (A New Age Dawns Part 1).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/04.- Solitary Ground.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/05.- Blank Infinity.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/06.- Force Of The Shore.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/07.- Quietus.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/08.- Mother Of Light (A New Age Dawns Part 2).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/09.- Trois Vierges.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/10.- Another Me In Lack'ech.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/11.- Consign To Oblivion (A New Age Dawns Part 3).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/01 Samadhi (prelude).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/02 Resign to Surrender (A New Age Dawns pt. IV).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/03 Unleashed.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/04 Martyr of the Free Word.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/05 Our Destiny.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/06 Kingdom of Heaven (A New Age Dawns, Part V).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/07 The Price Of Freedom (Interlude).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/08 Burn To A Cinder.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/09 Tides of Time.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/10 Deconstruct.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/11 Semblance of Liberty.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/13 Design Your Universe (A New Age Dawns pt. VI).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 13 - Beyond The Depth.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 01 - Vengeance Is Mine.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 02 - Unholy Trinity.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 03 - The Valley.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 04 - Caught In A Web.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 05 - Insomnia.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 06 - Under The Aegis.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 07 - Trois Vierges (Solo Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 08 - Mystica.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 09 - Valley Of Sins.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 10 - Empty Gaze.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 11 - The Alleged Paradigm.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 12 - Supremacy.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 14 - Epitome.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 15 - Inevitable Embrace.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 16 - Angel Of Death.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 17 - The Ultimate Return.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 18 - Trois Vierges (Reprise).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 19 - Solitary Ground (Single Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 20 - Quietus (Score Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/01. Adyta (The Neverending Embrace).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/02. Sensorium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/03. Cry for the Moon (The Embrace that Smothers - Part IV).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/04. Feint.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/05. Illusive Consensus.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/06. Façade of Reality (The Embrace that Smothers - Part V).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/07. Run for a Fall.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/08. Seif al Din (The Embrace that Smothers - Part VI).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/09. The Phantom Agony.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/01_Prologue.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/02_Center of the Universe.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/03_Farewell.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/04_Interlude I (Opiate Soul).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/05_The Edge of Paradise.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/06_Wander.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/07_Interlude II (Omen).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/08_Descent of the Archangel.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/09_Interlude III (At the Banquet).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/10_A Feast for the Vain.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/11_On the Coldest Winter Night.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/12_Lost & Damned.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/13_Helena's Theme.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/14_Interlude IV (Dawn).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/15_The Mourning After (Carry On).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/16_III Ways to Epica.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/17_Snow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 01 - Originem.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 02 - The Second Stone.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 03 - The Essence Of Silence.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 04 - Victims Of Contingency.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 05 - Sense Without Sanity (The Impervious Code).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 06 - Unchain Utopia.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 07 - The Fifth Guardian (Interlude).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 08 - Chemical Insomnia.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 09 - Reverence (Living In The Heart).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 10 - Omen (The Ghoulish Malady).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 11 - Canvas Of Life.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 12 - Natural Corruption.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 13 - The Quantum Enigma (Kingdom Of Heaven Part II).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 14 - Dreamscape.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD2 - Acoustic Tracks/Epica - 01 - Canvas Of Life (Acoustic Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD2 - Acoustic Tracks/Epica - 02 - In All Conscience (Acoustic Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD2 - Acoustic Tracks/Epica - 03 - Dreamscape (Acoustic Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD2 - Acoustic Tracks/Epica - 04 - Natural Corruption (Acoustic Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 01 - Originem (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 02 - The Second Stone (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 03 - The Essence Of Silence (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 04 - Victims Of Contingency (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 05 - Sense Without Sanity (The Impervious Code) (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 06 - Unchain Utopia (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 07 - The Fifth Guardian (Interlude) (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 08 - Chemical Insomnia (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 09 - Reverence (Living In The Heart) (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 10 - Omen (The Ghoulish Malady) (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 11 - Canvas Of Life (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 12 - Natural Corruption (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 13 - The Quantum Enigma (Kingdom Of Heaven Part II) (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Anima.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Avalanche.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Deep Water Horizon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Delirium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Guilty Demeanor.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Internal Warfare.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Karma.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Monopoly On Truth.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Requiem For The Indifferent.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Serenade Of Self-Destruction.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Stay The Course.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Storm The Sorrow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Twin Flames (Soundtrack Version) (Bonus Track).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/01-epica-eidola.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/02-epica-edge_of_the_blade.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/03-epica-a_phantasmic_parade.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/04-epica-universal_death_squad.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/05-epica-divide_and_conquer.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/06-epica-beyond_the_matrix.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/07-epica-once_upon_a_nightmare.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/08-epica-the_cosmic_algorithm.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/09-epica-ascension_-_dream_state_armageddon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/10-epica-dancing_in_a_hurricane.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/11-epica-tear_down_your_walls.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/12-epica-the_holographic_principle_-_a_profound_understanding_of_reality.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/13-epica-beyond_the_good_the_bad_and_the_ugly.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/14-epica-dancing_in_a_gypsy_camp.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/15-epica-immortal_melancholy_(acoustic_version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/16-epica-the_funky_algorithm.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/17-epica-universal_love_squad.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/01 - The Solace System.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/02 - Fight Your Demons.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/03 - Architect of Light.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/04 - Wheel of Destiny.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/05 - Immortal Melancholy.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/06 - Decoded Poetry.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/01. Crimson Bow and Arrow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/02. Wings of Freedom.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/03. If Inside These Walls Was a House.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/04. Dedicate Your Heart!.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/05. Crimson Bow and Arrow (Instrumental).mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/06. Wings of Freedom (Instrumental).mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/07. If Inside These Walls Was a House (Instrumental).mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/08. Dedicate Your Heart! (Instrumental).mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/01 - The Solace System.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/02 - Fight Your Demons.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/03 - Architect of Light.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/04 - Wheel of Destiny.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/05 - Immortal Melancholy.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/06 - Decoded Poetry.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Anima.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Avalanche.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Deep Water Horizon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Delirium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Guilty Demeanor.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Internal Warfare.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Karma.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Monopoly On Truth.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Requiem For The Indifferent.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Serenade Of Self-Destruction.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Stay The Course.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Storm The Sorrow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Twin Flames (Soundtrack Version) (Bonus Track).mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_08 - Retrospect - Live 2013 - Never Enough.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_18 - Retrospect - Live 2013 - Battle of The HeroesThe Imperial March.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_01 - Retrospect - Live 2013 - Intro.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_02 - Retrospect - Live 2013 - Monopoly On Truth.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_03 - Retrospect - Live 2013 - Sensorium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_04 - Retrospect - Live 2013 - Unleashed.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_05 - Retrospect - Live 2013 - Martyr Of The Free World.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_06 - Retrospect - Live 2013 - Chasing The Dragon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_07 - Retrospect - Live 2013 - Presto (Vivaldi Cover).mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_09 - Retrospect - Live 2013 - Stabat Mater Dolorosa (With Foor Jansen).mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_10 - Retrospect - Live 2013 - Twin Flames.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_11 - Retrospect - Live 2013 - Serenade Of Self Destruction.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_12 - Retrospect - Live 2013 - FeintFools Of DamnationMother Of LightKingdom Of HeavenRun For A FallDeep Water Horizon - Orchestra Cover.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_13 - Retrospect - Live 2013 - The Divine Conspiracy.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_14 - Retrospect - Live 2013 - Delirium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_15 - Retrospect - Live 2013 - Blank Infinity.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_16 - Retrospect - Live 2013 - The Obsessive Devotion.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_17 - Retrospect - Live 2013 - Retrospect.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_19 - Retrospect - Live 2013 - Quietus.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_20 - Retrospect - Live 2013 - The Phantom Agony.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_21 - Retrospect - Live 2013 - Cry To The Moon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_22 - Retrospect - Live 2013 - Sancta Terra (With Floor Jansen).mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_23 - Retrospect - Live 2013 - Design Your Universe.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_24 - Retrospect - Live 2013 - Storm Of Sorrow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_25 - Retrospect - Live 2013 - Consign To Oblivion.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/202. Orchestral Medley.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/101. Introspect.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/102. Monopoly On Truth.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/103. Sensorium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/104. Unleashed.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/105. Martyr Of The Free Word.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/106. Chasing The Dragon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/107. Presto.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/108. Never Enough.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/109. Stabat Mater Dolorosa.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/110. Twin Flames.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/201. Serenade Of Self Destruction.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/203. The Divine Conspiracy ~Anniversary Edition~.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/204. Delirium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/205. Blank Infinity.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/206. The Obsessive Devotion.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/207. Retrospect.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/208. Battle Of The Heroes & Imperial March.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/209. Quietus.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/210. The Phantom Agony.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/301. Cry For The Moon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/302. Sancta Terra.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/303. Design Your Universe.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/304. Storm The Sorrow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/305. Consign To Oblivion.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/306. Outrospect.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 01.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 02.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 03.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 04.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 05.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 06.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 07.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 08.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 09.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 10.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 11.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 12.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 13.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 14.mp3
/home/pi/MediaFolder/mp3/The Skeleton Key - Omega Alive/Epica - The Skeleton Key - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Nov-Dec/Paul Elstak - Hey Mambo.mp3
/home/pi/MediaFolder/mp3/2024 Apr-Jul/Paul Elstak - TAKE ME AWAY.mp3
/home/pi/MediaFolder/mp3/Magiczne i chuj/Paul Elstak - TAKE ME AWAY.mp3
/home/pi/MediaFolder/mp3/Youtube/DJ Paul Elstak You're A Hardcore Hooligan [am4Ww4g0XtM].mp3
/home/pi/MediaFolder/mp3/Youtube/DJ Paul Elstak, New Kids - Turbo (D-Fence Decade Mix) [AQrk2-B_Irg].mp3
/home/pi/MediaFolder/mp3/Youtube/Rooler & Sickmode & Paul Elstak - TAKE ME AWAY (Official Video) [ifKnpGKeKdk].mp3
/home/pi/MediaFolder/mp3/Youtube/FiNCH x PAUL ELSTAK - GABBER GIRL (prod. Paul Elstak, Dasmo & Mania Music) [Official Video] 4k [3smGQOexuSU].mp3
/home/pi/MediaFolder/mp3/Youtube/New Kids Feat. Paul Elstak - Turbo (Official German Video HD) [HKF4hobJl2A].mp3
/home/pi/MediaFolder/mp3/Youtube/Paul Elstak - Full set - Intents Festival 2024 [WVzwkPDiLTc].mp3
/home/pi/MediaFolder/mp3/Youtube/Paul Elstak x GPF x Boogshe - Vet En Hard (Official Video) [5xVx127afSA].mp3
/home/pi/MediaFolder/mp3/Muzyka/2016/SABATON - The Lost Battalion (OFFICIAL LYRIC VIDEO) - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2016/SABATON - Blood of Bannockburn (OFFICIAL LYRIC VIDEO) - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/10 Urodziny Klubu Spi Katowice AronChupa Spiowi Mocni - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/ANGEL WITCH - live from Headbangers Open Air (Full Song) - from www.streetclip.tv - YouTube_1.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Arabskie (garett22)/Best Arabic Nasheed ever 2013 - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Arabskie (garett22)/ISISTEP - ALLAHU AKBAR REMIX VIDEO 2015 ISIS - YouTube(1).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Arabskie (garett22)/ISISTEP - ALLAHU AKBAR REMIX VIDEO 2015 ISIS - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Arabskie (garett22)/My Ummah, Dawn Has Appeared (METAL v2.0) - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Arabskie (garett22)/Ummeti Kad Laha Fecrun امي ق لاح فجر Best Ever Nasheed - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/GAMMA RAY - Dethrone Tyranny 9. 2011 [HD] Berlin Live - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Gemini Abyss Jest Taki Samotny Dom COVER - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/My Ummah, Dawn Has Appeared Nasheed - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Angel Witch/ANGEL WITCH - live from Headbangers Open Air (Full Song) - from www.streetclip.tv - YouTube_1.mp3
/home/pi/MediaFolder/mp3/Muzyka/2019/ŁYDKA GRUBASA - Rapapara (Oficjalny Teledysk) Woodstock 2018 - YouTube.mp3
/home/pi/MediaFolder/mp3/Youtube/1 HOUR Dark Techno EBM Industrial Bass Mix 'SABBATH' [Copyright Free] [9Wz3J1P5HZY].mp3
/home/pi/MediaFolder/mp3/Youtube/100 twarzy grzybiarzy - przejebane [FfO8IBwi4t0].mp3
/home/pi/MediaFolder/mp3/Youtube/3 AM SOLO-Q (FRENCHCORE MIX) [G9kzYRJU3aQ].mp3
/home/pi/MediaFolder/mp3/Youtube/3Blokes & Villain - Shoey In Ya Face Power Hour Records [hNQ2dG8hYug].mp3
/home/pi/MediaFolder/mp3/Youtube/Ada Karczmarczyk ADU - Miss Messianist [2v8V0CepOE4].mp3
/home/pi/MediaFolder/mp3/Youtube/Adu & Monarowcy - W Monarze [MhTFGm596wM].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Bit z Serca Jezusa [h9QBUsBQDOk].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Bursztynami mnie obejmij [_OV1_X9sA68].mp3
/home/pi/MediaFolder/mp3/Youtube/DJ Paul Elstak You're A Hardcore Hooligan [am4Ww4g0XtM].mp3
/home/pi/MediaFolder/mp3/Youtube/DJ Paul Elstak, New Kids - Turbo (D-Fence Decade Mix) [AQrk2-B_Irg].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock & Billx - Mother Earth (Official Video) [2kCklVUxOsM].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock & Da Mouth of Madness ft. Ally The Piper - Trip to Scotland [oIYDEfEDmfw].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock & Partyraiser LIVE @ Dominator 2023 - Voyage of the Damned [0-RVGPrMEBI].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock & Sefa present Symphony of Freedom (Defqon.1 at Home, 2021) [vN6Jy50vOz8].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock & Zyklon - Trip To Japan [OwcHGm-GF9I].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock - Trip to Ireland [GvrvQTUbUcA].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock @ REBiRTH Festival 2023 [m2z_1bEs8Ug].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock Hellbound 2023 Hemkade [S2sSfN5t8AY].mp3
/home/pi/MediaFolder/mp3/Youtube/Early Hardcore Lenny Dee vs. DJ Paul - Make It Fucking Louder [CWs_-sW1-0w].mp3
/home/pi/MediaFolder/mp3/Youtube/ANKOR - Darkbeat [OFFICIAL VIDEO] - Chapter 1 [aTKwR1YxAwg].mp3
/home/pi/MediaFolder/mp3/Youtube/ANKOR - Winner Horse [OFFICIAL VIDEO] [Wuy8EQAzjh0].mp3
/home/pi/MediaFolder/mp3/Youtube/APNOIE - Recollections (Official Video) darkTunes Music Group [na55cP7nxvs].mp3
/home/pi/MediaFolder/mp3/Youtube/Babymetal - Headbanger (Momoko ver.) (Legend MM 2024 Live) Eng Subs [19nntDDbYdg].mp3
/home/pi/MediaFolder/mp3/Youtube/Babymetal - Headbanger (Night of 20 version) (Live Proshot) [uTN9wE82Xpc].mp3
/home/pi/MediaFolder/mp3/Youtube/Babymetal - Live @ Rock am Ring 2024 #RAR2024 [gmj6QLdLxRY].mp3
/home/pi/MediaFolder/mp3/Youtube/BABYMETAL x @ElectricCallboy - RATATATA (OFFICIAL Live Music Video at FOX_FEST) [ChmVcJK7N-c].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - EMBRIONY NA TRONY !!! [ykVsqBPcLXI].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Orzeł we mnie [hsI5nzaRSbk].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon Amarth - Raise Your Horns (Live) 4K [fPCfUa2pd9o].mp3
/home/pi/MediaFolder/mp3/Youtube/AniMe Defqon.1 Weekend Festival 2019 [-0SX2g5gt_s].mp3
/home/pi/MediaFolder/mp3/Youtube/BABYMETAL x @ElectricCallboy - RATATATA (OFFICIAL VIDEO) [EDnIEWyVIlE].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx - Imagination Festival Rave Music [T5ZEL_gGxEM].mp3
/home/pi/MediaFolder/mp3/Youtube/DJ AniMe - Masters of Hardcore Spain 2023 (Fabrik - Madrid) [ASGGaUwk6Qg].mp3
/home/pi/MediaFolder/mp3/Youtube/Electric Callboy - Hypa Hypa (Alex feat. Aga vocal cover) po polsku [JIJ29a9V5UY].mp3
/home/pi/MediaFolder/mp3/Youtube/FEUERSCHWANZ - I See Fire (Ed Sheeran Cover) Napalm Records [F-8JYS1uXC8].mp3
/home/pi/MediaFolder/mp3/Youtube/If SYSTEM OF A DOWN wrote 'MACARENA' [GfMIvH41BzQ].mp3
/home/pi/MediaFolder/mp3/Youtube/Mutilator Defqon.1 2024 [7Qy72qM16Xo].mp3
/home/pi/MediaFolder/mp3/Youtube/Reverze 2024 Sefa [L2wChuOaes0].mp3
/home/pi/MediaFolder/mp3/Youtube/SYNDICATE 2022 Miss K8 vs. AniMe [1myM-zVArcQ].mp3
/home/pi/MediaFolder/mp3/Youtube/TUNAK TUNAK TUN METAL VERSION Bloodywood Feat. Bonde do Metaleiro [APK2iGKK7gs].mp3
/home/pi/MediaFolder/mp3/Youtube/Rooler & Sickmode & Paul Elstak - TAKE ME AWAY (Official Video) [ifKnpGKeKdk].mp3
/home/pi/MediaFolder/mp3/Youtube/Scooter - The Chaser Jigga Jigga! [hJjCefEbAA0].mp3
/home/pi/MediaFolder/mp3/Youtube/Sefa & Headhunterz - (ID Als Alles Duister Is) [UDWDcYcrbqQ].mp3
/home/pi/MediaFolder/mp3/Youtube/SEFA (DJ-set) SLAM! [ZoUZlrvOvmo].mp3
/home/pi/MediaFolder/mp3/Youtube/SEFA @ DEFQON.1 2017 (FULL SET) [fc8n2u-VbZI].mp3
/home/pi/MediaFolder/mp3/Youtube/SEFA @ HARMONY OF HARDCORE 2018 (LIVE WITH PIANO) [BIXRHtSLBic].mp3
/home/pi/MediaFolder/mp3/Youtube/Sefa @ Reverze 2022 [REUPLOAD] [-5ZgWmSqGdo].mp3
/home/pi/MediaFolder/mp3/Youtube/Sefa Defqon.1 Theatre 2023 FULL [D_jG6CHl1NY].mp3
/home/pi/MediaFolder/mp3/Youtube/Sefa Defqon 1 theatre - full set [YQr2iA8vcjA].mp3
/home/pi/MediaFolder/mp3/Youtube/Sefa Defqon.1 Weekend Festival 2019 [m9bRC92OsfI].mp3
/home/pi/MediaFolder/mp3/Youtube/Shinzou Wo Sasageyo (Attack On Titan) - Metal Cover Feat. Rob Lundgren! [Mo_Y5XZPGgc].mp3
/home/pi/MediaFolder/mp3/Youtube/Sweet but Psycho - Ava Max (Metal Cover) [ckswcYvfeFg].mp3
/home/pi/MediaFolder/mp3/Youtube/FiNCH x PAUL ELSTAK - GABBER GIRL (prod. Paul Elstak, Dasmo & Mania Music) [Official Video] 4k [3smGQOexuSU].mp3
/home/pi/MediaFolder/mp3/Youtube/Frenchcore Familia I Defqon.1 Weekend Festival 2023 I Thursday I BLACK [i_MZvopQHE8].mp3
/home/pi/MediaFolder/mp3/Youtube/Frenchcore Mix 2023 #11 [ZOz3Ph3WZdY].mp3
/home/pi/MediaFolder/mp3/Youtube/GPF & J1zzy - King Of The Pieps (Official Video) [F5B84XsUYJ8].mp3
/home/pi/MediaFolder/mp3/Youtube/If BLACK SABBATH wrote 'JOLENE' [YRAheVxhuIA].mp3
/home/pi/MediaFolder/mp3/Youtube/If Rammstein wrote 'Every Breath You Take' [_j9Vm3t1HHI].mp3
/home/pi/MediaFolder/mp3/Youtube/If Rammstein wrote 'Poison' [bNStVF7SsTE].mp3
/home/pi/MediaFolder/mp3/Youtube/If Rammstein wrote 'You Spin Me Round' [6ufauqY2Rn4].mp3
/home/pi/MediaFolder/mp3/Youtube/If Sepultura wrote 'Whenever, Wherever' [GvMrxnQg1hI].mp3
/home/pi/MediaFolder/mp3/Youtube/If SLAYER wrote 'JUMP' [E_pj1LWBZZA].mp3
/home/pi/MediaFolder/mp3/Youtube/If SLAYER wrote 'SWEET DREAMS' [tz8VNzX_IHs].mp3
/home/pi/MediaFolder/mp3/Youtube/If System Of A Down wrote 'Livin' La Vida Loca' [bsxQ6MN4mrA].mp3
/home/pi/MediaFolder/mp3/Youtube/Jak się myje kibel Epic Viking Folk [EYFOzJZsO3A].mp3
/home/pi/MediaFolder/mp3/Youtube/JAM Project - THE HERO !! (One Punch Man OP)┃Raon Lee x PelleK [5u-1VVWM9l0].mp3
/home/pi/MediaFolder/mp3/Youtube/JKLL & Dr. Peacock ft. Ellene Masri - Hit The Road Jack [Mt6nfbeRpe8].mp3
/home/pi/MediaFolder/mp3/Youtube/Koncert ADU na ŚDM w Krakowie - Jaraj się Marią [xkOQds-lQDk].mp3
/home/pi/MediaFolder/mp3/Youtube/KUPOWANIE BILETU NA MECZ LIGI MISTRZÓW ALE TO EUROBEAT [zM2X0a_z6a8].mp3
/home/pi/MediaFolder/mp3/Youtube/LET 3 - Mama ŠČ! Official video Eurovision 2023 [O_tmsim6lPY].mp3
/home/pi/MediaFolder/mp3/Youtube/Linked Horizon - Shinzo wo Sasageyo! (LIVE) Attack on Titan Opening 3 [2YNQYYHT8Uc].mp3
/home/pi/MediaFolder/mp3/Youtube/Linked Horizon Attack on Titan OPENINGS LIVE [FhM402sKgqA].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx - Tree of Life (Psy to Hard)[Official video] ☯️ [HM-zIwaZr1A].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx Dominator Festival 2022 - Hell of a Ride [5Y6PUQcD5hU].mp3
/home/pi/MediaFolder/mp3/Youtube/BRING ME THE HORIZON ⧸⧸ KINGSLAYER ft. BABYMETAL 【NEX_FEST】 [pAM8MQt6I6I].mp3
/home/pi/MediaFolder/mp3/Youtube/BWSP Fałszywy Raszyn [EKHSkMYhgkY].mp3
/home/pi/MediaFolder/mp3/Youtube/DARK TECHNO MIX Andrea Botez [4K] [M_aOXL5Sg4I].mp3
/home/pi/MediaFolder/mp3/Youtube/dArtagnan - Farewell ft. Patty Gurdy [ckSEnb_I3Zg].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 2018 Sefa [-sfrrxEW158].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Legends 2023 Sunday [JuyNNkxbbFA].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2018 POWER HOUR [QdGz0OHQ9S8].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2019 POWER HOUR [vJ2eHsQv7Ac].mp3
/home/pi/MediaFolder/mp3/Youtube/DJ AniMe - Hard Techno Hardcore Mix [B2KuebFsfN4].mp3
/home/pi/MediaFolder/mp3/Youtube/Syndicate 2023 D-Fence vs AniMe [oLAOmeoI2Dc].mp3
/home/pi/MediaFolder/mp3/Youtube/Syntetic - Nagi Szopen [tXcUOUZqX1Y].mp3
/home/pi/MediaFolder/mp3/Youtube/The Hero ONE-PUNCH MAN (Full) feat. Angelo Bissanti ワンパンマン [NSG32WJX6-c].mp3
/home/pi/MediaFolder/mp3/Youtube/The Syntetic - Człowiek Widmo [yS0Lv2Pv99g].mp3
/home/pi/MediaFolder/mp3/Youtube/The Syntetic - Hollywood [3Psr2H9A90A].mp3
/home/pi/MediaFolder/mp3/Youtube/The Syntetic - Kleopatra [Jtf6q7_LX_Y].mp3
/home/pi/MediaFolder/mp3/Youtube/The Syntetic - Niewidzialny Templariusz [DlzNRywOe9Q].mp3
/home/pi/MediaFolder/mp3/Youtube/This Is Sefa Defqon.1 2022 [5mEWXmS3cnM].mp3
/home/pi/MediaFolder/mp3/Youtube/This Is Sefa The Spotlight Defqon.1 2024 [TR7mmkZuIuk].mp3
/home/pi/MediaFolder/mp3/Youtube/Thunderdome 2023 Dr. Peacock [7kZCTY77K9k].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon Amarth - Raise Your Horns (Official Video) [Ndu33Uv7Aco].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon Amarth - Raven's Flight [H24S0nym-pE].mp3
/home/pi/MediaFolder/mp3/Youtube/AMON AMARTH- Raise Your Horns ( Live 2016 ) [KwEJWrx8bLg].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon amarth-Raise your horns live (Hellfest) 2016 [voGBBSw_fFo].mp3
/home/pi/MediaFolder/mp3/Youtube/Anime - Imagination Festival Hardcore [SWgZ9YPwhhM].mp3
/home/pi/MediaFolder/mp3/Youtube/AniMe @ Dominator Festival 2023 - Voyage of the Damned [caCjlVO7ZGA].mp3
/home/pi/MediaFolder/mp3/Youtube/AniMe @ Masters of Hardcore 2022 - Magnum Opus [NHc4Lne0mFA].mp3
/home/pi/MediaFolder/mp3/Youtube/AniMe BLACK SUGAR 2022 EQ Music Poland [H4jHMo1EB34].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Sensualna ( cover Sexualna Mirami) [519hvggfQtM].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Zabierz mnie do Arsenału [kX2W6t-z7xo].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - CHILDREN OF THE INTERNET [do7jTWPpn2c].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - Church is a girl [evdx4YdCv6I].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - Hej husarzu! NIE_PODLE_głości dzień [SReTynvd6ek].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - HOUSTON, HOUSTON [C9Vlw4jB7iM].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - Na Święta chcę Ciebie (Wędrowcu w potrzebie) [IMwMUr2NvSg].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - niUNIA EUROPEJSKA [itrYkDzdAkw].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - RODZINA TO... [R2mmHMembrg].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU feat MATEJKO - Nie strzelam do zdrajców oczami [PGL6Q9G4_JM].mp3
/home/pi/MediaFolder/mp3/Youtube/All Time Low - Kids In The Dark (Official Music Video) [SaIegdJxTsE].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon Amarth - Raise Your Horns #Woodstock2017 [YCDkAT6671c].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon Amarth - Raise Your Horns (Live At Summer Breeze) [jVOluNDjc5s].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Idź do światła i nie pierdol! [13e4n5UxylU].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Intronizacja Chrystusa na Króla w korporacjach [pVyBe-FdTDk].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - JARAJ SIĘ MARIĄ [7EzpQoDfVyo].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - JP2 in da house [cOZZa7ycovY].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Lecimy ze Smoleńska z powrotem [f3CVfG4pV8M].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Na Tinderze w dobrej wierze [QuWYrH8knzk].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Nie chcę w lewo, nie chcę w prawo [J3Ok-KcbQ80].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Niszcz szatana Łaską Pana [LNyC6YA8NO8].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Oddam ciało, oddam duszę (by już nie być prekariuszem) [4LjmMj3Gyyo].mp3
/home/pi/MediaFolder/mp3/Youtube/Van Halen Ain't Talkin' 'Bout Love 1986 [b1NmPFgdt6Y].mp3
/home/pi/MediaFolder/mp3/Youtube/We Must Fight - President Reagan (Long Version) [JDVT-8tUfiE].mp3
/home/pi/MediaFolder/mp3/Youtube/Występ ADU na THE ARTISTS 2015 - God is the biggest director [Rkp6QaDdO6A].mp3
/home/pi/MediaFolder/mp3/Youtube/Yousei Teikoku - Patriot Anthem live HQ Sub Engita [HK3ZN5bpr-M].mp3
/home/pi/MediaFolder/mp3/Youtube/[Official Video] JAM Project - THE HERO !! - 2015.11.29 in Yokohama Arena - One Punch Man [NL-iKNk1FyU].mp3
/home/pi/MediaFolder/mp3/Youtube/[Official Video] Yousei Teikoku - Astral Dogma - 妖精帝國 [_EeYxtAeaX4].mp3
/home/pi/MediaFolder/mp3/Youtube/[Official Video] Yousei Teikoku - Kuusou Mesorogiwi - 空想メソロギヰ 妖精帝國 [ZZvJY7_gyfw].mp3
/home/pi/MediaFolder/mp3/Youtube/「Nightcore Empyre One Hands Up Mix」 [PUh8uiR7Dao].mp3
/home/pi/MediaFolder/mp3/Youtube/和楽器バンド 千本桜 [K_xTet06SUo].mp3
/home/pi/MediaFolder/mp3/Youtube/💛🤍"Barka - Mała Armia Janosika w Watykanie🎻(150 .górali gra dla Jana Pawła II w dniu Jego urodzin) [NaRRlqd-uaE].mp3
/home/pi/MediaFolder/mp3/Youtube/Barka - Agnieszka Cudzich (live) [e74D5FmtXow].mp3
/home/pi/MediaFolder/mp3/Youtube/New Kids Feat. Paul Elstak - Turbo (Official German Video HD) [HKF4hobJl2A].mp3
/home/pi/MediaFolder/mp3/Youtube/OBERSCHLESIEN - Król Olch [OFFICIAL VIDEO] [KPJPJzpk_QQ].mp3
/home/pi/MediaFolder/mp3/Youtube/One Punch Man FULL ENGLISH OPENING (The Hero - Jam Project) Cover by Jonathan Young [XMCYNH1EJTg].mp3
/home/pi/MediaFolder/mp3/Youtube/Orkiestra online #wdomuzagrane - Co mi Panie dasz (arr. Adam Sztaba) [7NSXXttiwHw].mp3
/home/pi/MediaFolder/mp3/Youtube/Paul Elstak - Full set - Intents Festival 2024 [WVzwkPDiLTc].mp3
/home/pi/MediaFolder/mp3/Youtube/Paul Elstak x GPF x Boogshe - Vet En Hard (Official Video) [5xVx127afSA].mp3
/home/pi/MediaFolder/mp3/Youtube/Peacock in Concert - Mad Masquerade Show 2023 Silverdome Zoetermeer NL [OWM8dP1WbUk].mp3
/home/pi/MediaFolder/mp3/Youtube/POWER HOUR 2022 Defqon.1 Weekend Festival Sixty minutes of pure insanity [fX1kUoeUhPg].mp3
/home/pi/MediaFolder/mp3/Youtube/POWER HOUR 2023 Defqon.1 Weekend Festival This is Madness [A7thBilOLFU].mp3
/home/pi/MediaFolder/mp3/Youtube/Power Hour Six Years of Insanity Defqon.1 at Home 2020 [HiMTwi3_09U].mp3
/home/pi/MediaFolder/mp3/Youtube/Q-dance Presents The Hardstyle Top 40 September 2024 [aTAvXvfw-pg].mp3
/home/pi/MediaFolder/mp3/Youtube/Reverze 2024 Dr. Peacock [L6nKIyiCmLA].mp3
/home/pi/MediaFolder/mp3/Youtube/Barka (Electro Remix) [WQsaVznexqw].mp3
/home/pi/MediaFolder/mp3/Youtube/Barka - ukochana pieśń Jana Pawła II [0qzLRlQFFQ4].mp3
/home/pi/MediaFolder/mp3/Youtube/Best Of Globus Epic Vocal Rock Orchestral [FS0Csetvl4M].mp3
/home/pi/MediaFolder/mp3/Youtube/best summer song 2024 Hardstyle Remix Best Hardstyle Remixes Of Popular Songs 2024 [9oGZ9fCW8FM].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx & Neika - Chichovite (Frenchcore to Hardtek)[Official video]☯️ [EGDwQbXBpZc].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx & Otyken - My wing (Rave music edit) [ylUsbg-yUZ8].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx & Vandal - Rolling Paper Hard edit free remix (Official video) [fi7U24itRaQ].mp3
/home/pi/MediaFolder/mp3/Youtube/Electric Callboy - Live @ Rock am Ring 2024 #RAR2024 [jQN23aw8oaI].mp3
/home/pi/MediaFolder/mp3/Youtube/Electric Callboy - We Got the Moves #polandrock2024 [KNyQP5ql6pY].mp3
/home/pi/MediaFolder/mp3/Youtube/ELECTRIC CALLBOY ft BABYMETAL - RATATATA (Live at Resurrection Fest EG 2024) [R78nx63OfPg].mp3
/home/pi/MediaFolder/mp3/Youtube/ELYOSE - Les artisans du chaosDe guerre lasse (Live at the Halloween Horror Night 2016, Paris) [Bf_XofH9j0E].mp3
/home/pi/MediaFolder/mp3/Youtube/Eurodance & Bubblegum EDM Mix Tinzo [zvXAt1uB6ME].mp3
-191
View File
@@ -1,191 +0,0 @@
# FILEPATH: /home/mtuszowski/conjurer/conjurer_musician/radio_conjurer.liq
# This script sets up a Liquidsoap radio stream with various features and configurations.
# Load icecast credentials from a JSON file
let json.parse credentials = file.contents("/home/pi/Conjurer/icecast_credentials.json")
# Enable replaygain metadata processing
enable_replaygain_metadata()
# Set up a playlog for tracking played tracks
l = playlog(duration = 72000.0, persistency="/home/pi/Conjurer/persistence.log")
# Function to check if a track can be played based on its metadata
def check(r)
m = request.metadata(r)
if l.last(m) < 36000. then
log.info("Rejecting #{m['filename']} (played #{l.last(m)}s ago).")
false
else
l.add(m)
true
end
end
# Define playlists to be used in the stream
s1 = replaygain(playlist(reload_mode="watch", check_next=check, "/home/pi/Conjurer/all_playlist.playlist"))
s2 = replaygain(playlist(reload_mode="watch", check_next=check, "/home/pi/Conjurer/priority_queue.playlist"))
s3 = replaygain(playlist(reload_mode="watch", check_next=check, "/home/pi/Conjurer/hit.playlist"))
# Create a request queue for user-generated requests
requests_queue = request.queue()
# Function to process the request queue and add new requests
def queue_processing()
text=file.lines("/home/pi/Conjurer/request.playlist")
if text != [] then
list.iter(fun(item) -> requests_queue.push.uri(item), text)
file.remove("/home/pi/Conjurer/request.playlist")
f = file.open("/home/pi/Conjurer/request.playlist", create=true)
f.close()
end
end
# Configure output formats and destinations
def now_playing(m)
# raw lookup ("" if missing)
raw_title = m["title"]
raw_artist = m["artist"]
# default if empty
title = if raw_title == "" then "Unknown" else raw_title end
artist = if raw_artist == "" then "Unknown" else raw_artist end
log.critical("Now playing #{artist} - #{title}")
# write it out
system("echo '#{artist} - #{title}' > /tmp/now_playing.txt")
m
end
# Randomly select a playlist with weights
s4 = random(id="randomizer", weights=[2, 3, 5], [s1, s2, s3])
# Load jingles playlist
jingles = (playlist(reload_mode="watch", "/home/pi/Conjurer/jingles.playlist"))
# Create the main stream with random playlist and jingles
s = rotate(id="randomizer", weights=[10, 1], [s4, jingles])
s = crossfade(fade_out=2., fade_in=2., duration=4., fallback(id="switcher", track_sensitive=true, [requests_queue, s]))
s = metadata.map(now_playing, s)
# Set up an interactive harbor for controlling the stream
interactive.harbor(port = 9999)
# Set up interactive controls for bass boost
f = interactive.float("f", description="Frequency", min=0., max=1000., unit="Hz", 200.)
g = interactive.float("g", description="Gain", min=0., max=20., unit="dB", 8.)
b = bass_boost(frequency=f, gain=g, s)
s = add([s, b])
# Set up interactive control for main volume
a = interactive.float("main_volume", min=0., max=20., 1.1)
s = compress.multiband.interactive(bands=7, s)
mic_gain = interactive.float("mic_volume", min=0., max=120., 0.5)
# Apply audio processing effects
tmic = buffer(input.pulseaudio()) # Microphone
mic = amplify(mic_gain, tmic)
mic = gate(threshold=-80., range=-120., mic)
mic = compress(threshold=0., ratio=2.,mic)
mic = nrj(normalize(mic))
mic = blank.strip(max_blank=15., min_noise=.1, threshold=-30., mic)
mic = fallback(id="switcher2", track_sensitive=false, [mic, blank()])
# Apply audio processing effects
s = nrj(s)
s = amplify(a, s)
# Skip blank sections in the stream
s = blank.skip(max_blank=10., s)
#Manual audition override
live_enabled = interactive.bool("Going Live!", true)
s = add([mic,s])
s=switch(track_sensitive=true,
[(live_enabled, mic),
({true}, s)])
# Configure logging settings
log_to_stdout = true
log_to_file = true
logpath = "/home/pi/Conjurer/radio_log.log"
loglevel = 3
set("log.stdout", log_to_stdout)
set("log.level", loglevel)
# Enable logging to file
set("log.file", log_to_file)
set("log.file.path", logpath)
# Set up emergency fallback track
emergency = single("/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock - Trip to Ireland [GvrvQTUbUcA].mp3")
radio = fallback(id="switcher2", track_sensitive=false, [s, emergency])
# Set up an interactive control for skipping tracks
p = interactive.bool("Skip track", false)
def http_skip(~protocol, ~data, ~headers, uri)=
radio.skip()
http.response(code=200,data="Skipped")
end
harbor.http.register(port=54321,method="GET","/skip", http_skip)
# Function to process the request queue and skip the current track if requested
def check_skip()
if p() then
log.info("Skipping current track.")
radio.skip()
p.set(false)
end
end
# Run the queue processing function every 60 seconds
thread.run(every=60., queue_processing)
# Run the check_skip function every 5 seconds
thread.run(every=15., check_skip)
# Enable persistent script parameters
interactive.persistent("script.params")
# Configure output formats and destinations
output.icecast(%mp3, host="radio", port=8000, password=credentials.password, icy_metadata="true", mount="mp3-stream", radio)
output.pulseaudio(radio)
#output.file.hls("/tmp/hls", [("mp3-low", %mp3(bitrate=96)), ("mp3-hi", %mp3(bitrate=160))], radio)
# Uncomment the following lines to enable additional output formats
# output.icecast(%opus, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="opus-stream", radio)
# output.icecast(%ogg, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="ogg-stream", radio)
# output.icecast(%aac, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="aac-stream", radio)
# output.icecast(%flac, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="flac-stream", radio)
# output.icecast(%vorbis, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="vorbis-stream", radio)
# output.icecast(%speex, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="speex-stream", radio)
# output.icecast(%wav, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="wav-stream", radio)
# output.icecast(%pcm, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="pcm-stream", radio)
# output.icecast(%raw, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="raw-stream", radio)
# output.icecast(%s16l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s16l-stream", radio)
# output.icecast(%s16b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s16b-stream", radio)
# output.icecast(%s24l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s24l-stream", radio)
# output.icecast(%s24b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s24b-stream", radio)
# output.icecast(%s32l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s32l-stream", radio)
# output.icecast(%s32b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s32b-stream", radio)
# output.icecast(%s64l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s64l-stream", radio)
# output.icecast(%s64b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s64b-stream", radio)
# output.icecast(%s128l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s128l-stream", radio)
# output.icecast(%s128b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s128b-stream", radio)
# output.icecast(%s256l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s256l-stream", radio)
# output.icecast(%s256b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s256b-stream", radio)
# output.icecast(%s512l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s512l-stream", radio)
# output.icecast(%s512b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s512b-stream", radio)
# output.icecast(%s1024l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s1024l-stream", radio)
# output.icecast(%s1024b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s1024b-stream", radio)
# output.icecast(%s2048l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s2048l-stream", radio)
# output.icecast(%s2048b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s2048b-stream", radio)
# output.icecast(%s4096l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s4096l-stream", radio)
# output.icecast(%s4096b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s4096b-stream", radio)
# output.icecast(%s8192l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s8192l-stream", radio)
# output.icecast(%s8192b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s8192b-stream", radio)
View File
-4
View File
@@ -1,4 +0,0 @@
flask
waitress
sshtunnel
requests
-195
View File
@@ -1,195 +0,0 @@
{
"string": [],
"bool": [ [ "Skip track", false ], [ "Going Live!", false ] ],
"int": [],
"float": [
[
"mic_volume",
0.0
],
[
"compress_gain6",
0.1
],
[
"compress_ratio6",
7.9
],
[
"compress_threshold6",
-15.8
],
[
"compress_release6",
30.0
],
[
"compress_attack6",
30.0
],
[
"compress_frequency6",
18610.0
],
[
"compress_gain5",
5.4
],
[
"compress_ratio5",
4.8
],
[
"compress_threshold5",
-13.6
],
[
"compress_release5",
120.0
],
[
"compress_attack5",
160.0
],
[
"compress_frequency5",
13950.0
],
[
"compress_gain4",
6.5
],
[
"compress_ratio4",
4.0
],
[
"compress_threshold4",
-12.2
],
[
"compress_release4",
130.0
],
[
"compress_attack4",
200.0
],
[
"compress_frequency4",
3890.0
],
[
"compress_gain3",
5.5
],
[
"compress_ratio3",
3.5
],
[
"compress_threshold3",
-11.7
],
[
"compress_release3",
140.0
],
[
"compress_attack3",
250.0
],
[
"compress_frequency3",
2270.0
],
[
"compress_gain2",
3.3
],
[
"compress_ratio2",
3.9
],
[
"compress_threshold2",
-11.5
],
[
"compress_release2",
120.0
],
[
"compress_attack2",
250.0
],
[
"compress_frequency2",
1920.0
],
[
"compress_gain1",
5.6
],
[
"compress_ratio1",
3.4
],
[
"compress_threshold1",
-12.2
],
[
"compress_release1",
120.0
],
[
"compress_attack1",
220.0
],
[
"compress_frequency1",
650.0
],
[
"compress_gain0",
7.5
],
[
"compress_ratio0",
3.2
],
[
"compress_threshold0",
-13.1
],
[
"compress_release0",
110.0
],
[
"compress_attack0",
140.0
],
[
"compress_frequency0",
110.0
],
[
"compress_wet",
1.0
],
[
"main_volume",
1.8
],
[
"g",
1.0
],
[
"f",
106.4
]
]
}
File diff suppressed because it is too large Load Diff
-672
View File
@@ -1,672 +0,0 @@
"""
The provided Python script sets up a Flask web server to manage a list of music files, with
functions for rescanning the music folder, updating the music list, and serving the music list via
API endpoints.
"""
import json
import logging
import os
import random
import re
import threading
import time
from datetime import datetime
from logging import handlers
from pathlib import Path
from typing import Dict, List
import requests
from flask import (
Flask,
abort,
jsonify,
redirect,
render_template,
request,
send_from_directory,
)
from waitress import serve
import media_search_functions
def _env(name: str, default: str) -> str:
return os.getenv(name, default)
def _env_path(name: str, default: str) -> Path:
value = os.getenv(name, default)
return Path(value).expanduser().resolve()
API_KEY = os.getenv("CONJURER_API_KEY")
MAIN_BOT_ADDRESS = _env("CONJURER_MAIN_BOT", "http://127.0.0.1:5000")
MUSIC_TRACKER = _env("CONJURER_MUSIC_TRACKER_ENDPOINT", "/prepped_tracks")
HOST_ADDRESS = _env("CONJURER_MUSICIAN_HOST", "0.0.0.0")
PORT_ADDRESS = int(_env("CONJURER_MUSICIAN_PORT", "5000"))
BASE_DIR = Path(
os.getenv("CONJURER_MUSICIAN_BASE", str(Path(__file__).resolve().parent))
)
LOGFILE = _env_path(
"CONJURER_MUSICIAN_LOG", str(BASE_DIR / "discord_mus_service.log")
)
LOGSTORE = _env_path("CONJURER_LOGSTORE", str(BASE_DIR / "logs"))
MUSIC_FOLDER = _env_path(
"CONJURER_MUSIC_FOLDER", str(BASE_DIR / "music")
)
PRIORITY_FOLDER = _env_path(
"CONJURER_PRIORITY_FOLDER", str(MUSIC_FOLDER / "priority")
)
RADIOLOG_PATH = _env_path(
"CONJURER_RADIO_LOG", str(BASE_DIR / "radio_log.log")
)
PERSISTENCE_PATH = _env_path(
"CONJURER_PERSISTENCE_LOG", str(BASE_DIR / "persistence.log")
)
ALL_PLAYLIST_PATH = _env_path(
"CONJURER_ALL_PLAYLIST", str(BASE_DIR / "all_playlist.playlist")
)
HIT_PLAYLIST_PATH = _env_path(
"CONJURER_HIT_PLAYLIST", str(BASE_DIR / "hit.playlist")
)
REQUEST_PLAYLIST_PATH = _env_path(
"CONJURER_REQUEST_PLAYLIST", str(BASE_DIR / "request.playlist")
)
PRIORITY_PLAYLIST_PATH = _env_path(
"CONJURER_PRIORITY_PLAYLIST", str(BASE_DIR / "priority_queue.playlist")
)
STREAM_TEMPLATE = _env_path(
"CONJURER_STREAM_TEMPLATE", str(BASE_DIR / "stream.html")
)
ENCODING = _env("CONJURER_ENCODING", "utf-8")
SEPARATOR_FILE_PATH = os.sep
for playlist_path in (
ALL_PLAYLIST_PATH,
HIT_PLAYLIST_PATH,
REQUEST_PLAYLIST_PATH,
PRIORITY_PLAYLIST_PATH,
):
playlist_path.parent.mkdir(parents=True, exist_ok=True)
random.seed()
music_file_list: List[str] = []
priority_list: List[str] = []
def _build_headers() -> Dict[str, str]:
headers: Dict[str, str] = {}
if API_KEY:
headers["X-Conjurer-Api-Key"] = API_KEY
return headers
def _authorize_request() -> None:
if API_KEY and request.headers.get("X-Conjurer-Api-Key") != API_KEY:
abort(401)
def _post_to_bot(payload: List[str]) -> None:
response = requests.post(
f"{MAIN_BOT_ADDRESS}{MUSIC_TRACKER}",
json=payload,
headers=_build_headers(),
timeout=60,
)
logger = logging.getLogger("conjurer_musician")
logger.info("SENT")
logger.info(response.status_code)
logger.info("SEND CONFIRMED")
def rescan():
"""
The `rescan` function logs a message, scans for mp3 files in a specified folder,
and adds them to a list of music files.
"""
logger = logging.getLogger("conjurer_musician")
logger.info("Rescan triggered")
music_file_list.clear()
priority_list.clear()
for mp3_item in MUSIC_FOLDER.glob("**/*.mp3"):
temp_music_file = mp3_item.as_posix()
if os.name == "nt":
temp_music_file = temp_music_file.replace("/", "\\")
music_file_list.append(temp_music_file)
for mp3_item in PRIORITY_FOLDER.glob("**/*.mp3"):
temp_music_file = mp3_item.as_posix()
if os.name == "nt":
temp_music_file = temp_music_file.replace("/", "\\")
priority_list.append(temp_music_file)
with ALL_PLAYLIST_PATH.open("w", encoding=ENCODING) as w_file:
try:
for item in music_file_list:
w_file.write(item)
w_file.write("\n")
except json.JSONDecodeError:
pass
with HIT_PLAYLIST_PATH.open("w", encoding=ENCODING) as w_file:
try:
for item in priority_list:
w_file.write(item)
w_file.write("\n")
except json.JSONDecodeError:
pass
def thread_rescan():
"""
The `thread_rescan` function periodically triggers a rescan operation after a specified time
interval.
"""
logger = logging.getLogger("conjurer_musician")
logger.info("Starting filesystemupdater")
while True:
time.sleep(60 * 60 * 24)
logger.info("Rescan triggered")
rescan()
def scan_tracks():
# Set the filename and open the file
logger = logging.getLogger("conjurer_musician")
with open(RADIOLOG_PATH, "r", encoding=ENCODING) as log_file:
log_file.seek(os.stat(RADIOLOG_PATH).st_size)
prev_size = os.stat(PERSISTENCE_PATH).st_size
while True:
current_size = os.stat(PERSISTENCE_PATH).st_size
if prev_size != current_size:
while prev_size != current_size:
prev_size = current_size
time.sleep(0.1)
current_size = os.stat(PERSISTENCE_PATH).st_size
with open(PERSISTENCE_PATH, "r", encoding=ENCODING) as persistence:
lines = persistence.readlines()
if len(lines) >= 3:
_post_to_bot(["next", lines[2]])
position = log_file.tell()
line = log_file.readline()
if not line:
time.sleep(1)
log_file.seek(position)
continue
if not re.match(r".*Prepared.*", line):
time.sleep(0.1)
continue
result = None
if re.match(r".*jingles.*", line):
result = ["jingles", line]
elif re.match(r".*priority.*", line):
result = ["priority", line]
elif re.match(r".*hit.*", line):
result = ["hit", line]
elif re.match(r".*all_playlist.*", line):
result = ["all", line]
elif re.match(r".*request.*", line):
result = ["requests", line]
if result:
logger.info("Forwarding radio log entry: %s", result[0])
_post_to_bot(result)
time.sleep(0.1)
app = Flask(__name__)
# AutoIndex(app, browse_root="/")
# TODO: Odpalić wyszukiwarki w wątkach i dopiero po wszystkim zsumować wyszukiwanie.
def wyszukaj(word_list, how_many, _logger=None, return_to_bot=True):
"""
Searches for music files based on a list of keywords and returns a list of matching files.
Args:
word_list (list): A list of keywords to search for.
how_many (int): The maximum number of matching files to return.
Returns:
list: A list of matching files, sorted by their search weight.
"""
if _logger is None:
fun_logger = logging.getLogger()
else:
fun_logger = _logger
return_list = []
search_weight = []
for _ in range(len(music_file_list)):
search_weight.append((0, ""))
time_start = datetime.now()
if int(how_many) > 0:
skip_start = 2
else:
skip_start = 1
for word in word_list[skip_start:]:
token_weight = len(word)
fun_logger.info("Słowo kluczowe: %s", word)
itr = 0
for file in music_file_list:
file = file.split(SEPARATOR_FILE_PATH)
char_remove = [
".",
"^",
"$",
"*",
"+",
"?",
"{",
"}",
"[",
"]",
"\\",
"/",
"|",
"(",
")",
"!",
",",
"-",
":",
"mp3",
]
all_words = []
for f_iter in file:
for char in char_remove:
f_iter = remove_characters(f_iter, char)
tmp = f_iter.split()
all_words.extend(tmp)
pingu = 1
pattern_len = len(all_words)
if platform == "win32":
skip = 2
else:
skip = 4
matched_times = 1
# TODO: To do wątków albo for asynchroniczny
for itm in all_words[skip:]:
pingu += 1
pattern = ".*" + word + ".*"
if re.match(pattern, itm, re.IGNORECASE):
temp_weight = (
search_weight[itr][0]
+ (token_weight + (pingu**1.5) / pattern_len) / matched_times
)
search_weight[itr] = (
temp_weight,
music_file_list[itr],
)
matched_times += 1
itr += 1
fun_logger.info(
"Stworzylem tablice wag zajęło mi to %s", datetime.now() - time_start
)
time_start = datetime.now()
item_to_search = max_weight(search_weight)
itr = 0
if item_to_search == 0:
return []
not_found = True
return_list = []
if int(how_many) <= 0:
fun_logger.info("Jeden plik do zagrania")
while not_found:
if search_weight[itr][0] == item_to_search:
return_list.append(search_weight[itr])
if not return_to_bot:
with PRIORITY_PLAYLIST_PATH.open("a", encoding=ENCODING) as s_file:
s_file.write(search_weight[itr][1] + "\n")
break
itr += 1
else:
fun_logger.info("Wiele plików do zagrania")
search_weight.sort(key=lambda x: x[0], reverse=True)
return_list.extend(search_weight[: int(how_many)])
fun_logger.info("Done: %s", return_list)
return return_list
def max_weight(lista):
"""
Take a list of weights and return the maximum weight.
:param lista: It seems like the parameter `lista` is a list of items, possibly representing weights.
The function name `max_weight` suggests that the function is intended to find the maximum weight
from the list. However, without more context or information about the problem, it's difficult to say
for sure what the
"""
maximum_weight = 0
for iterator in lista:
if iterator[0] > maximum_weight:
maximum_weight = iterator[0]
return maximum_weight
def remove_characters(string, character):
"""
The `remove_characters` function removes all occurrences of a specified character from a given
string.
:param string: The string parameter is the input string from which characters will be removed
:param character: The character parameter is the character that you want to remove from the string
:return: a new string where all occurrences of the specified character have been removed.
"""
return string.replace(character, "")
@app.route('/get_share_list', methods=['POST'])
def get_share_list():
_authorize_request()
data = request.get_json()
entries = data.get('entries')
keywords = data.get('keywords')
# Validate entries
if not isinstance(entries, int) or not (1 <= entries <= 10):
return jsonify({'error': '"entries" must be an integer between 1 and 10.'}), 400
# Validate keywords list
if not isinstance(keywords, list) or not all(isinstance(k, str) for k in keywords):
return jsonify({'error': '"keywords" must be a list of strings.'}), 400
# Call external search
files = media_search_functions.find_matches(entries, keywords)
# Return each file path as a JSON list
return jsonify({'files': files}), 200
@app.route('/get_share_links', methods=['POST'])
def get_share_links():
_authorize_request()
data = request.get_json()
file_paths = data.get('file_paths')
# Validate file_paths list
if not isinstance(file_paths, list) or not all(isinstance(p, str) for p in file_paths):
return jsonify({'error': '"file_paths" must be a list of strings.'}), 400
# Call external publish
links = media_search_functions.publish(file_paths)
# Return list of published links
return jsonify({'links': links}), 200
@app.route("/stream", methods=["GET"])
def stream_music():
"""
The function `stream_music` is a route handler for the "/stream" endpoint.
It returns a JSON response containing a key "music_file_list" with the value of the variable `music_file_list`.
:return: A JSON response containing a key "music_file_list" with the value of the variable `music_file_list`.
"""
# return send_from_directory("/tmp/hls", "stream.m3u8")
return render_template(str(STREAM_TEMPLATE))
@app.route("/<string:file_name>")
def stream(file_name):
"""
Stream the specified file from the video directory.
Args:
file_name (str): The name of the file to be streamed.
Returns:
Response: The response containing the streamed file.
"""
# trunk-ignore(bandit/B108)
video_dir = "/tmp/hls"
return send_from_directory(video_dir, file_name)
@app.route("/stream_mp3", methods=["GET"])
def stream_music_mp3():
"""
The function `stream_music_mp3` is a route handler for the "/stream_mp3" endpoint.
It redirects the user to the URL "http://www.example.com" with a status code of 302.
:return: A redirect response to "http://www.example.com" with a status code of 302.
"""
return redirect("http://www.example.com", code=302)
@app.route("/clear_pr_pls", methods=["GET"])
def clear_pr_pls():
_authorize_request()
"""
The function `clear_pr_pls` clears the contents of the priority queue playlist file.
:return: A JSON response indicating the success of the operation.
"""
app.logger.info("CLEARING PLAYLIST")
with PRIORITY_PLAYLIST_PATH.open("w", encoding=ENCODING) as cleared_pl:
cleared_pl.write("")
return_data = jsonify(isError=False, message="Success", statusCode=200, data=[])
return return_data, 200
@app.route("/mp3", methods=["GET"])
def get_music_list():
"""
The function `get_music_list` returns a JSON object containing a list of music files.
:return: A JSON response containing a key "music_file_list" with the value of the variable
`music_file_list`.
"""
return jsonify({"music_file_list": music_file_list})
@app.route("/update_mp3", methods=["POST"])
def update_music_list():
"""
The function `update_music_list` receives a POST request with a JSON payload, logs the received
item, adds it to a music file list, and returns a success message along with the updated record.
:return: The function `update_music_list` is returning a tuple containing a JSON response and a
status code. The JSON response includes keys `isError`, `message`, `statusCode`, and `data`,
with values indicating the success of the operation and the data that was
received and added to the `music_file_list`.
The status code returned is 200, indicating a successful response.
"""
_authorize_request()
record = json.loads(request.data)
app.logger.info(record["item"])
music_file_list.append(record["item"])
return_data = (
jsonify(isError=False, message="Success", statusCode=200, data=record),
200,
)
return return_data
@app.route("/get_music", methods=["POST"])
def look_for_playlist():
"""
The function `look_for_playlist` receives a POST request with a JSON payload, logs the received
item, adds it to a music file list, and returns a success message along with the updated record.
:return: A tuple containing a JSON response and a status code. The JSON response includes keys `isError`,
`message`, `statusCode`, and `data`, with values indicating the success of the operation and the
data that was received and added to the `music_file_list`. The status code returned is 200,
indicating a successful response.
"""
_authorize_request()
record = json.loads(request.data)
app.logger.info(record)
app.logger.info(record["lista_slow"])
app.logger.info(record["UUID"])
app.logger.info(record["dlugosc_plejlisty"])
return_data = wyszukaj(
record["lista_slow"], record["dlugosc_plejlisty"], app.logger, True
)
return_data = (
jsonify(isError=False, message="Success", statusCode=200, data=return_data),
200,
)
return return_data
@app.route("/request_radio_file", methods=["POST"])
def add_request():
_authorize_request()
record = json.loads(request.data)
app.logger.info(record)
app.logger.info(record["lista_slow"])
app.logger.info(record["UUID"])
return_data = wyszukaj(record["lista_slow"], 0, app.logger, False)
with REQUEST_PLAYLIST_PATH.open("a", encoding=ENCODING) as s_file:
for item in return_data:
s_file.write(item[1] + "\n")
return_data = (
jsonify(
isError=False, message="Success", statusCode=200, data={"status": "OK"}
),
200,
)
return return_data
@app.route("/create_priority_playlist", methods=["POST"])
def create_priority_playlist():
"""
The function `create_priority_playlist` receives a POST request with a JSON payload, logs the received
item, adds it to a music file list, and returns a success message along with the updated record.
:return: A tuple containing a JSON response and a status code.
The JSON response includes keys `isError`,
`message`, `statusCode`, and `data`, with values
indicating the success of the operation and the
data that was received and added to the `music_file_list`.
The status code returned is 200,indicating a successful response.
"""
_authorize_request()
record = json.loads(request.data)
app.logger.info(record)
app.logger.info(record["lista_slow"])
app.logger.info(record["UUID"])
app.logger.info(record["dlugosc_plejlisty"])
return_data = wyszukaj(
record["lista_slow"], record["dlugosc_plejlisty"], app.logger, False
)
random.shuffle(return_data)
with REQUEST_PLAYLIST_PATH.open("a", encoding=ENCODING) as s_file:
for item in return_data:
s_file.write(item[1] + "\n")
return_data = (
jsonify(
isError=False, message="Success", statusCode=200, data={"status": "OK"}
),
200,
)
return return_data
@app.route("/add_to_priority", methods=["POST"])
def add_to_priority():
"""
The function `add_to_priority` receives a POST request with a JSON payload, logs the received
item, adds it to a music file list, and returns a success message along with the updated record.
:return: A tuple containing a JSON response and a status code.
The JSON response includes keys `isError`,
`message`, `statusCode`, and `data`, with values
indicating the success of the operation and the
data that was received and added to the `music_file_list`.
The status code returned is 200,indicating a successful response.
"""
_authorize_request()
record = json.loads(request.data)
app.logger.info(record)
app.logger.info(record["lista_slow"])
app.logger.info(record["UUID"])
app.logger.info(record["dlugosc_plejlisty"])
return_data = wyszukaj(
record["lista_slow"], record["dlugosc_plejlisty"], app.logger, False
)
with PRIORITY_PLAYLIST_PATH.open("a", encoding=ENCODING) as s_file:
for item in return_data:
s_file.write(item[1] + "\n")
return_data = (
jsonify(
isError=False, message="Success", statusCode=200, data={"status": "OK"}
),
200,
)
return return_data
def flask_debug():
"""
The `flask_debug` function starts a Flask application in debug mode without using the reloader.
Do not use for production for fucks sake.
"""
# trunk-ignore(bandit/B201)
app.run(debug=True, use_reloader=False, host=HOST_ADDRESS, port=PORT_ADDRESS)
def waitress_run():
"""
The `waitress_run` function serves the `app` on host HOST_ADDRESS
and port 5000 using the Waitress WSGI server.
This function starts the Waitress server and listens for incoming requests
on the specified host and port. It uses the `serve` function from the Waitress
library to handle the serving process.
Parameters:
None
Returns:
None
"""
serve(app, host=HOST_ADDRESS, port=PORT_ADDRESS)
if __name__ == "__main__":
logger = logging.getLogger("conjurer_musician")
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
handler = handlers.RotatingFileHandler(
filename=LOGFILE,
encoding=ENCODING,
mode="a",
maxBytes=6 * 1024 * 1024,
backupCount=6,
)
handler.setFormatter(formatter)
logger.addHandler(handler)
rescan()
logger.info("Started")
threads = []
# threads.append(threading.Thread(target=flask_debug))
threads.append(threading.Thread(target=waitress_run, daemon=True))
threads.append(threading.Thread(target=thread_rescan, daemon=True))
for worker in threads:
worker.start()
time.sleep(60)
track_thread = threading.Thread(target=scan_tracks, daemon=True)
track_thread.start()
try:
for worker in threads:
worker.join()
track_thread.join()
except KeyboardInterrupt:
logger.info("Shutdown requested - exiting musician service")
View File
@@ -1,3 +0,0 @@
{
"password" : "RadioHardkor123#!"
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-8
View File
@@ -1,8 +0,0 @@
jingiel2.mp3
jingiel3.mp3
jingiel4.mp3
jingiel.mp3
/home/pi/MediaFolder/mp3/Youtube/Pine Tree Riots - We'll Have Our Home Again [ctpfRxvC0JQ].mp3
/home/pi/MediaFolder/mp3/2024 Jan-Mar/Rave The Reqviem - Oh, the Joy!.mp3
/home/pi/MediaFolder/mp3/2022 Aug-Oct/Wil Farr - Keep Your Rifle by Your Side.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/The Hope County Choir - Keep Your Rifle by Your Side - Choir Version.mp3
@@ -1,52 +0,0 @@
#!/usr/bin/env python3
import argparse
import json
import os
import sys
import uuid
from pathlib import Path
# CONFIGURATION
JSON_DB = '/var/log/share_scan.json'
SHARE_DIR = Path('/var/www/html/share')
BASE_URL = 'https://czernobog.pl/share'
# Ensure share directory exists
SHARE_DIR.mkdir(parents=True, exist_ok=True)
def load_db():
with open(JSON_DB) as f:
return json.load(f)['entries']
ENTRIES = load_db()
def relevancy(path, keywords):
score = 0
low = path.lower()
for kw in keywords:
if kw.lower() in low:
score += low.count(kw.lower())
return score
def find_matches(count, keywords):
scored = []
for e in ENTRIES:
score = relevancy(e['path'], keywords)
if score > 0:
scored.append((score, e['path']))
scored.sort(reverse=True, key=lambda x: x[0])
result = [p for _, p in scored]
return result[:count]
def publish(paths):
urls = []
for path in paths:
token = uuid.uuid4().hex
link = SHARE_DIR / token
try:
os.symlink(path, link)
except FileExistsError:
pass
urls.append(f"{BASE_URL}/{token}")
return urls
@@ -1,8 +0,0 @@
/home/pi/MediaFolder/mp3/Youtube/POWER HOUR 2022 Defqon.1 Weekend Festival Sixty minutes of pure insanity [fX1kUoeUhPg].mp3
/home/pi/MediaFolder/mp3/Youtube/POWER HOUR 2023 Defqon.1 Weekend Festival This is Madness [A7thBilOLFU].mp3
/home/pi/MediaFolder/mp3/Youtube/POWER HOUR Defqon.1 2024 [jXBtF_QBBI0].mp3
/home/pi/MediaFolder/mp3/Youtube/POWERWOLF - Thunderpriest (Official Lyric Video) [3WzC_1eWoKE].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2015 POWER HOUR [npSqR01ly9g].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2017 POWER HOUR [8g9z25yA8dA].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2018 POWER HOUR [QdGz0OHQ9S8].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2019 POWER HOUR [vJ2eHsQv7Ac].mp3
@@ -1,541 +0,0 @@
/home/pi/MediaFolder/mp3/Muzyka/2016/Funker Vogt/Funker Vogt - Words Of Power (Grubotronit)/Funker Vogt - Words of Power - 04 - Words of Power (Power mix).mp3halen_cover)-radial.mp3pi/MediaFolder/mp3/2021 Selection/Epica - Beyond the Matrix.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Crimson Bow and Arrow.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Edge of the Blade.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Gaia.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Sensorium.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - The Essence of Silence.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - The Skeleton Key.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Unchain Utopia - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Universal Death Squad.mp3
/home/pi/MediaFolder/mp3/2021 Selection/Epica - Universal Love Squad.mp3
/home/pi/MediaFolder/mp3/2022 Apr-Jul/Epica - Beyond the Matrix - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Apr-Jul/Epica - Kingdom of Heaven, Pt. 3 - The Antediluvian Universe - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Apr-Jul/Epica - Rivers - A Capella - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/Epica - Beyond the Matrix - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/Epica - Kingdom of Heaven, Pt. 3 - The Antediluvian Universe - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/Epica - Rivers - A Capella - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/Epica - Sacred & Wild.mp3
/home/pi/MediaFolder/mp3/2022 Jan-Mar/Epica - The Last Crusade - A New Age Dawns 1.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Freedom - The Wolves Within -.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Abyss O'Time.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Abyss of Time - Countdown to Singularity -.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Crimson Bow and Arrow - Instrumental.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Crystal Mountain - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Dedicate Your Heart! - Instrumental.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - El Código Vital.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Martyr of the Free Word.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Never Enough.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Omegacoustic.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Rivers - A Capella.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Rivers.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Storm the Sorrow.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - The Skeleton Key.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Unchain Utopia - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Unchain Utopia.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Unleashed - Live At The AFAS Live.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Unleashed.mp3
/home/pi/MediaFolder/mp3/2023 Apr-Jul/Epica - Wheel of Destiny.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Design Your Universe - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Omega - Sovereign of the Sun Spheres -.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Abyss O'Time.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Abyss of Time - Countdown to Singularity - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Battle of the Heroes & Imperial March - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Burn to a Cinder.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Chasing the Dragon - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Cry for the Moon (The Embrace That Smothers , Pt. 4).mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Cry For The Moon - Sahara Dust Demo.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Dance Of Fate - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Dancing in a Gypsy Camp.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Decoded Poetry.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Dedicate Your Heart!.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Design Your Universe - A New Age Dawns, Pt. 6 - Acoustic Version.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Design Your Universe - A New Age Dawns, Pt. 6.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Falsches Spiel - Run For A Fall - German version.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Façade Of Reality (The Embrace That Smothers, Pt. V) - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Fight Your Demons.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Illusive Consensus - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Illusive Consensus - Sahara Dust demo.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Kingdom of Heaven - A New Age Dawns, Pt. 5.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Kingdom of Heaven Prt. 3 - The Antediluvian Universe -.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Kingdom of Heaven, Pt. 1 - A New Age Dawns Part V - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Kingdom of Heaven, Pt. 3 - The Antediluvian Universe - - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Martyr of the Free Word - Acoustic Version.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Martyr of the Free Word - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Martyr of the Free Word.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Omega - Sovereign of the Sun Spheres - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Omegacoustic.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Resign to Surrender - A New Age Dawns, Pt. 4.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Run For A Fall - Live Acoustic.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Run For A Fall - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Run for a Fall.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Seif al Din (The Embrace That Smothers, Pt. VI) - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Sensorium - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Sensorium - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Sensorium.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Divine Conspiracy ~Anniversary Edition~ - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Last Crusade - A New Age Dawns 1.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Last Crusade - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Phantom Agony - Live At Paradiso.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Phantom Agony - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Price of Freedom - Interlude.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Skeleton Key - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - The Solace System.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Twin Flames - Live.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Unchain Utopia - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Unchain Utopia.mp3
/home/pi/MediaFolder/mp3/2023 Jan-Mar/Epica - Wings of Freedom.mp3
/home/pi/MediaFolder/mp3/2024 Jan-Mar/Epica - Sancta Terra.mp3
/home/pi/MediaFolder/mp3/Magiczne i chuj/Epica - Never Enough.mp3
/home/pi/MediaFolder/mp3/Magiczne i chuj/Epica, Shining - The Final Lullaby (feat. Shining).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/01_-_Epica_-_Indigo.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/02_-_Epica_-_The_obsessive_devotion.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/03_-_Epica_-_Menace_of_vanity.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/04_-_Epica_-_Chasing_the_dragon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/05_-_Epica_-_Never_enough.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/06_-_Epica_-_La'fetach_chataz_rovetz.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/07_-_Epica_-_Death_of_a_dream.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/08_-_Epica_-_Living_a_lie.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/09_-_Epica_-_Fools_of_damnation.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/10_-_Epica_-_Beyond_belief.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/11_-_Epica_-_Safeguard_to_paradise.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/12_-_Epica_-_Sancta_terra.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica (2007) - The Divine Conspiracy/Epica (2007) - The Divine Conspiracy/13_-_Epica_-_The_divine_conspiracy.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/01 Palladium (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/02 Dies Irae (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/03 Ombra Mai Fu (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/04 Adagio (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/05 Spiderman Medley (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/06 Presto (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/07 Montagues & Capulets (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/08 The Imperial March (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/09 Stabat Mater Dolorosa (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/10 Unholy Trinity (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/11 In the Hall of the Mountain King (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy/12 Pirates Of The Caribbean (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/13 Indigo (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/14 The Last Crusade (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/15 Sensorium (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/16 Quietus (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/17 Chasing the Dragon (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/18_Epica_Feint.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/19_Epica_Never Enough.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/20_Epica_Beyond Belief.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/21 Cry for the Moon (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/22 Safeguard to Paradise (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/23 Blank Infinity (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/24 Living a Lie (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/25 The Phantom Agony (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/26 Sancta Terra (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/27 Illusive Consensus (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - 2009 - The Classical Conspiracy/Epica - 2009 - The Classical Conspiracy/classical conspiracy 2/28 Consign To Oblivion (live).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/01.- Hunab K'u (A New Age Dawns Prologue).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/02.- Dance Of Fate.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/03.- The Last Crusade (A New Age Dawns Part 1).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/04.- Solitary Ground.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/05.- Blank Infinity.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/06.- Force Of The Shore.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/07.- Quietus.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/08.- Mother Of Light (A New Age Dawns Part 2).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/09.- Trois Vierges.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/10.- Another Me In Lack'ech.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Consign To Oblivion 2005/Epica - Consign To Oblivion 2005/11.- Consign To Oblivion (A New Age Dawns Part 3).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/01 Samadhi (prelude).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/02 Resign to Surrender (A New Age Dawns pt. IV).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/03 Unleashed.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/04 Martyr of the Free Word.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/05 Our Destiny.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/06 Kingdom of Heaven (A New Age Dawns, Part V).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/07 The Price Of Freedom (Interlude).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/08 Burn To A Cinder.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/09 Tides of Time.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/10 Deconstruct.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/11 Semblance of Liberty.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - Design Your Universe (2009)/Epica - Design Your Universe (2009)/13 Design Your Universe (A New Age Dawns pt. VI).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 13 - Beyond The Depth.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 01 - Vengeance Is Mine.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 02 - Unholy Trinity.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 03 - The Valley.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 04 - Caught In A Web.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 05 - Insomnia.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 06 - Under The Aegis.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 07 - Trois Vierges (Solo Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 08 - Mystica.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 09 - Valley Of Sins.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 10 - Empty Gaze.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 11 - The Alleged Paradigm.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 12 - Supremacy.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 14 - Epitome.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 15 - Inevitable Embrace.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 16 - Angel Of Death.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 17 - The Ultimate Return.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 18 - Trois Vierges (Reprise).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 19 - Solitary Ground (Single Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica - The Score - An Epic Journey/Epica - 2005 - The Score - An Epic Journey (OST)/Epica - 20 - Quietus (Score Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/01. Adyta (The Neverending Embrace).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/02. Sensorium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/03. Cry for the Moon (The Embrace that Smothers - Part IV).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/04. Feint.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/05. Illusive Consensus.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/06. Façade of Reality (The Embrace that Smothers - Part V).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/07. Run for a Fall.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/08. Seif al Din (The Embrace that Smothers - Part VI).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Epica/Epica- The Phantom Agony/Epica- The Phantom Agony/09. The Phantom Agony.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/01_Prologue.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/02_Center of the Universe.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/03_Farewell.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/04_Interlude I (Opiate Soul).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/05_The Edge of Paradise.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/06_Wander.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/07_Interlude II (Omen).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/08_Descent of the Archangel.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/09_Interlude III (At the Banquet).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/10_A Feast for the Vain.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/11_On the Coldest Winter Night.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/12_Lost & Damned.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/13_Helena's Theme.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/14_Interlude IV (Dawn).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/15_The Mourning After (Carry On).mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/16_III Ways to Epica.mp3
/home/pi/MediaFolder/mp3/Muzyka/2010/Kamelot/Kamelot 2003 - Epica/17_Snow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 01 - Originem.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 02 - The Second Stone.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 03 - The Essence Of Silence.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 04 - Victims Of Contingency.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 05 - Sense Without Sanity (The Impervious Code).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 06 - Unchain Utopia.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 07 - The Fifth Guardian (Interlude).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 08 - Chemical Insomnia.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 09 - Reverence (Living In The Heart).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 10 - Omen (The Ghoulish Malady).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 11 - Canvas Of Life.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 12 - Natural Corruption.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 13 - The Quantum Enigma (Kingdom Of Heaven Part II).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD1 - The Quantum Enigma/Epica - 14 - Dreamscape.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD2 - Acoustic Tracks/Epica - 01 - Canvas Of Life (Acoustic Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD2 - Acoustic Tracks/Epica - 02 - In All Conscience (Acoustic Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD2 - Acoustic Tracks/Epica - 03 - Dreamscape (Acoustic Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD2 - Acoustic Tracks/Epica - 04 - Natural Corruption (Acoustic Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 01 - Originem (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 02 - The Second Stone (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 03 - The Essence Of Silence (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 04 - Victims Of Contingency (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 05 - Sense Without Sanity (The Impervious Code) (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 06 - Unchain Utopia (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 07 - The Fifth Guardian (Interlude) (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 08 - Chemical Insomnia (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 09 - Reverence (Living In The Heart) (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 10 - Omen (The Ghoulish Malady) (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 11 - Canvas Of Life (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 12 - Natural Corruption (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/CD3 - Instrumental Tracks/Epica - 13 - The Quantum Enigma (Kingdom Of Heaven Part II) (Instrumental Version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Anima.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Avalanche.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Deep Water Horizon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Delirium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Guilty Demeanor.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Internal Warfare.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Karma.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Monopoly On Truth.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Requiem For The Indifferent.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Serenade Of Self-Destruction.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Stay The Course.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Storm The Sorrow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - Requiem for the Indifferent/Epica - Twin Flames (Soundtrack Version) (Bonus Track).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/01-epica-eidola.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/02-epica-edge_of_the_blade.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/03-epica-a_phantasmic_parade.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/04-epica-universal_death_squad.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/05-epica-divide_and_conquer.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/06-epica-beyond_the_matrix.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/07-epica-once_upon_a_nightmare.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/08-epica-the_cosmic_algorithm.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/09-epica-ascension_-_dream_state_armageddon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/10-epica-dancing_in_a_hurricane.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/11-epica-tear_down_your_walls.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/12-epica-the_holographic_principle_-_a_profound_understanding_of_reality.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/13-epica-beyond_the_good_the_bad_and_the_ugly.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/14-epica-dancing_in_a_gypsy_camp.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/15-epica-immortal_melancholy_(acoustic_version).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/16-epica-the_funky_algorithm.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Holographic Principle 2016/17-epica-universal_love_squad.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/01 - The Solace System.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/02 - Fight Your Demons.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/03 - Architect of Light.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/04 - Wheel of Destiny.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/05 - Immortal Melancholy.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Epica/Epica - The Solace System [EP] (2017) DJmp-3.com/06 - Decoded Poetry.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/01. Crimson Bow and Arrow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/02. Wings of Freedom.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/03. If Inside These Walls Was a House.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/04. Dedicate Your Heart!.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/05. Crimson Bow and Arrow (Instrumental).mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/06. Wings of Freedom (Instrumental).mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/07. If Inside These Walls Was a House (Instrumental).mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - Epica vs Attack on Titan Songs (2017) EP/Epica - Epica vs Attack on Titan Songs (2017) EP/08. Dedicate Your Heart! (Instrumental).mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/01 - The Solace System.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/02 - Fight Your Demons.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/03 - Architect of Light.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/04 - Wheel of Destiny.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/05 - Immortal Melancholy.mp3
/home/pi/MediaFolder/mp3/Muzyka/2018/Epica - The Solace System [EP] (2017)/Epica - The Solace System [EP] (2017) DJmp-3.com/06 - Decoded Poetry.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Anima.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Avalanche.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Deep Water Horizon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Delirium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Guilty Demeanor.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Internal Warfare.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Karma.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Monopoly On Truth.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Requiem For The Indifferent.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Serenade Of Self-Destruction.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Stay The Course.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Storm The Sorrow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Requiem for the Indifferent/Epica - Requiem for the Indifferent/Epica - Twin Flames (Soundtrack Version) (Bonus Track).mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_08 - Retrospect - Live 2013 - Never Enough.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_18 - Retrospect - Live 2013 - Battle of The HeroesThe Imperial March.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_01 - Retrospect - Live 2013 - Intro.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_02 - Retrospect - Live 2013 - Monopoly On Truth.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_03 - Retrospect - Live 2013 - Sensorium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_04 - Retrospect - Live 2013 - Unleashed.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_05 - Retrospect - Live 2013 - Martyr Of The Free World.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_06 - Retrospect - Live 2013 - Chasing The Dragon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_07 - Retrospect - Live 2013 - Presto (Vivaldi Cover).mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_09 - Retrospect - Live 2013 - Stabat Mater Dolorosa (With Foor Jansen).mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_10 - Retrospect - Live 2013 - Twin Flames.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_11 - Retrospect - Live 2013 - Serenade Of Self Destruction.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_12 - Retrospect - Live 2013 - FeintFools Of DamnationMother Of LightKingdom Of HeavenRun For A FallDeep Water Horizon - Orchestra Cover.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_13 - Retrospect - Live 2013 - The Divine Conspiracy.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_14 - Retrospect - Live 2013 - Delirium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_15 - Retrospect - Live 2013 - Blank Infinity.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_16 - Retrospect - Live 2013 - The Obsessive Devotion.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_17 - Retrospect - Live 2013 - Retrospect.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_19 - Retrospect - Live 2013 - Quietus.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_20 - Retrospect - Live 2013 - The Phantom Agony.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_21 - Retrospect - Live 2013 - Cry To The Moon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_22 - Retrospect - Live 2013 - Sancta Terra (With Floor Jansen).mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_23 - Retrospect - Live 2013 - Design Your Universe.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_24 - Retrospect - Live 2013 - Storm Of Sorrow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/EPICA_-_Retrospect -Live 2013_MP3_REPACK (Yasmena)/EPICA_-_25 - Retrospect - Live 2013 - Consign To Oblivion.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/202. Orchestral Medley.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/101. Introspect.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/102. Monopoly On Truth.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/103. Sensorium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/104. Unleashed.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/105. Martyr Of The Free Word.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/106. Chasing The Dragon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/107. Presto.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/108. Never Enough.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/109. Stabat Mater Dolorosa.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/110. Twin Flames.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/201. Serenade Of Self Destruction.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/203. The Divine Conspiracy ~Anniversary Edition~.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/204. Delirium.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/205. Blank Infinity.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/206. The Obsessive Devotion.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/207. Retrospect.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/208. Battle Of The Heroes & Imperial March.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/209. Quietus.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/210. The Phantom Agony.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/301. Cry For The Moon.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/302. Sancta Terra.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/303. Design Your Universe.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/304. Storm The Sorrow.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/305. Consign To Oblivion.mp3
/home/pi/MediaFolder/mp3/Muzyka/2014/Epica - Retrospect 10th Anniversary (2013)/Epica - Retrospect 10th Anniversary (2013)/306. Outrospect.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 01.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 02.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 03.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 04.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 05.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 06.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 07.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 08.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 09.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 10.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 11.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 12.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 13.mp3
/home/pi/MediaFolder/mp3/Muzyka/Dream Of The Warrior - Gothic Rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia And More)/Dream of the warrior - Gothic rock (Epica,Edenbridge,Gathering,Nemesea,Nightwish,Sirenia and more)/Track 14.mp3
/home/pi/MediaFolder/mp3/The Skeleton Key - Omega Alive/Epica - The Skeleton Key - Omega Alive.mp3
/home/pi/MediaFolder/mp3/2023 Nov-Dec/Paul Elstak - Hey Mambo.mp3
/home/pi/MediaFolder/mp3/2024 Apr-Jul/Paul Elstak - TAKE ME AWAY.mp3
/home/pi/MediaFolder/mp3/Magiczne i chuj/Paul Elstak - TAKE ME AWAY.mp3
/home/pi/MediaFolder/mp3/Youtube/DJ Paul Elstak You're A Hardcore Hooligan [am4Ww4g0XtM].mp3
/home/pi/MediaFolder/mp3/Youtube/DJ Paul Elstak, New Kids - Turbo (D-Fence Decade Mix) [AQrk2-B_Irg].mp3
/home/pi/MediaFolder/mp3/Youtube/Rooler & Sickmode & Paul Elstak - TAKE ME AWAY (Official Video) [ifKnpGKeKdk].mp3
/home/pi/MediaFolder/mp3/Youtube/FiNCH x PAUL ELSTAK - GABBER GIRL (prod. Paul Elstak, Dasmo & Mania Music) [Official Video] 4k [3smGQOexuSU].mp3
/home/pi/MediaFolder/mp3/Youtube/New Kids Feat. Paul Elstak - Turbo (Official German Video HD) [HKF4hobJl2A].mp3
/home/pi/MediaFolder/mp3/Youtube/Paul Elstak - Full set - Intents Festival 2024 [WVzwkPDiLTc].mp3
/home/pi/MediaFolder/mp3/Youtube/Paul Elstak x GPF x Boogshe - Vet En Hard (Official Video) [5xVx127afSA].mp3
/home/pi/MediaFolder/mp3/Muzyka/2016/SABATON - The Lost Battalion (OFFICIAL LYRIC VIDEO) - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2016/SABATON - Blood of Bannockburn (OFFICIAL LYRIC VIDEO) - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/10 Urodziny Klubu Spi Katowice AronChupa Spiowi Mocni - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/ANGEL WITCH - live from Headbangers Open Air (Full Song) - from www.streetclip.tv - YouTube_1.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Arabskie (garett22)/Best Arabic Nasheed ever 2013 - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Arabskie (garett22)/ISISTEP - ALLAHU AKBAR REMIX VIDEO 2015 ISIS - YouTube(1).mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Arabskie (garett22)/ISISTEP - ALLAHU AKBAR REMIX VIDEO 2015 ISIS - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Arabskie (garett22)/My Ummah, Dawn Has Appeared (METAL v2.0) - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Arabskie (garett22)/Ummeti Kad Laha Fecrun امي ق لاح فجر Best Ever Nasheed - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/GAMMA RAY - Dethrone Tyranny 9. 2011 [HD] Berlin Live - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Gemini Abyss Jest Taki Samotny Dom COVER - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/My Ummah, Dawn Has Appeared Nasheed - YouTube.mp3
/home/pi/MediaFolder/mp3/Muzyka/2017/Angel Witch/ANGEL WITCH - live from Headbangers Open Air (Full Song) - from www.streetclip.tv - YouTube_1.mp3
/home/pi/MediaFolder/mp3/Muzyka/2019/ŁYDKA GRUBASA - Rapapara (Oficjalny Teledysk) Woodstock 2018 - YouTube.mp3
/home/pi/MediaFolder/mp3/Youtube/1 HOUR Dark Techno EBM Industrial Bass Mix 'SABBATH' [Copyright Free] [9Wz3J1P5HZY].mp3
/home/pi/MediaFolder/mp3/Youtube/100 twarzy grzybiarzy - przejebane [FfO8IBwi4t0].mp3
/home/pi/MediaFolder/mp3/Youtube/3 AM SOLO-Q (FRENCHCORE MIX) [G9kzYRJU3aQ].mp3
/home/pi/MediaFolder/mp3/Youtube/3Blokes & Villain - Shoey In Ya Face Power Hour Records [hNQ2dG8hYug].mp3
/home/pi/MediaFolder/mp3/Youtube/Ada Karczmarczyk ADU - Miss Messianist [2v8V0CepOE4].mp3
/home/pi/MediaFolder/mp3/Youtube/Adu & Monarowcy - W Monarze [MhTFGm596wM].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Bit z Serca Jezusa [h9QBUsBQDOk].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Bursztynami mnie obejmij [_OV1_X9sA68].mp3
/home/pi/MediaFolder/mp3/Youtube/DJ Paul Elstak You're A Hardcore Hooligan [am4Ww4g0XtM].mp3
/home/pi/MediaFolder/mp3/Youtube/DJ Paul Elstak, New Kids - Turbo (D-Fence Decade Mix) [AQrk2-B_Irg].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock & Billx - Mother Earth (Official Video) [2kCklVUxOsM].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock & Da Mouth of Madness ft. Ally The Piper - Trip to Scotland [oIYDEfEDmfw].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock & Partyraiser LIVE @ Dominator 2023 - Voyage of the Damned [0-RVGPrMEBI].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock & Sefa present Symphony of Freedom (Defqon.1 at Home, 2021) [vN6Jy50vOz8].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock & Zyklon - Trip To Japan [OwcHGm-GF9I].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock - Trip to Ireland [GvrvQTUbUcA].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock @ REBiRTH Festival 2023 [m2z_1bEs8Ug].mp3
/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock Hellbound 2023 Hemkade [S2sSfN5t8AY].mp3
/home/pi/MediaFolder/mp3/Youtube/Early Hardcore Lenny Dee vs. DJ Paul - Make It Fucking Louder [CWs_-sW1-0w].mp3
/home/pi/MediaFolder/mp3/Youtube/ANKOR - Darkbeat [OFFICIAL VIDEO] - Chapter 1 [aTKwR1YxAwg].mp3
/home/pi/MediaFolder/mp3/Youtube/ANKOR - Winner Horse [OFFICIAL VIDEO] [Wuy8EQAzjh0].mp3
/home/pi/MediaFolder/mp3/Youtube/APNOIE - Recollections (Official Video) darkTunes Music Group [na55cP7nxvs].mp3
/home/pi/MediaFolder/mp3/Youtube/Babymetal - Headbanger (Momoko ver.) (Legend MM 2024 Live) Eng Subs [19nntDDbYdg].mp3
/home/pi/MediaFolder/mp3/Youtube/Babymetal - Headbanger (Night of 20 version) (Live Proshot) [uTN9wE82Xpc].mp3
/home/pi/MediaFolder/mp3/Youtube/Babymetal - Live @ Rock am Ring 2024 #RAR2024 [gmj6QLdLxRY].mp3
/home/pi/MediaFolder/mp3/Youtube/BABYMETAL x @ElectricCallboy - RATATATA (OFFICIAL Live Music Video at FOX_FEST) [ChmVcJK7N-c].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - EMBRIONY NA TRONY !!! [ykVsqBPcLXI].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Orzeł we mnie [hsI5nzaRSbk].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon Amarth - Raise Your Horns (Live) 4K [fPCfUa2pd9o].mp3
/home/pi/MediaFolder/mp3/Youtube/AniMe Defqon.1 Weekend Festival 2019 [-0SX2g5gt_s].mp3
/home/pi/MediaFolder/mp3/Youtube/BABYMETAL x @ElectricCallboy - RATATATA (OFFICIAL VIDEO) [EDnIEWyVIlE].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx - Imagination Festival Rave Music [T5ZEL_gGxEM].mp3
/home/pi/MediaFolder/mp3/Youtube/DJ AniMe - Masters of Hardcore Spain 2023 (Fabrik - Madrid) [ASGGaUwk6Qg].mp3
/home/pi/MediaFolder/mp3/Youtube/Electric Callboy - Hypa Hypa (Alex feat. Aga vocal cover) po polsku [JIJ29a9V5UY].mp3
/home/pi/MediaFolder/mp3/Youtube/FEUERSCHWANZ - I See Fire (Ed Sheeran Cover) Napalm Records [F-8JYS1uXC8].mp3
/home/pi/MediaFolder/mp3/Youtube/If SYSTEM OF A DOWN wrote 'MACARENA' [GfMIvH41BzQ].mp3
/home/pi/MediaFolder/mp3/Youtube/Mutilator Defqon.1 2024 [7Qy72qM16Xo].mp3
/home/pi/MediaFolder/mp3/Youtube/Reverze 2024 Sefa [L2wChuOaes0].mp3
/home/pi/MediaFolder/mp3/Youtube/SYNDICATE 2022 Miss K8 vs. AniMe [1myM-zVArcQ].mp3
/home/pi/MediaFolder/mp3/Youtube/TUNAK TUNAK TUN METAL VERSION Bloodywood Feat. Bonde do Metaleiro [APK2iGKK7gs].mp3
/home/pi/MediaFolder/mp3/Youtube/Rooler & Sickmode & Paul Elstak - TAKE ME AWAY (Official Video) [ifKnpGKeKdk].mp3
/home/pi/MediaFolder/mp3/Youtube/Scooter - The Chaser Jigga Jigga! [hJjCefEbAA0].mp3
/home/pi/MediaFolder/mp3/Youtube/Sefa & Headhunterz - (ID Als Alles Duister Is) [UDWDcYcrbqQ].mp3
/home/pi/MediaFolder/mp3/Youtube/SEFA (DJ-set) SLAM! [ZoUZlrvOvmo].mp3
/home/pi/MediaFolder/mp3/Youtube/SEFA @ DEFQON.1 2017 (FULL SET) [fc8n2u-VbZI].mp3
/home/pi/MediaFolder/mp3/Youtube/SEFA @ HARMONY OF HARDCORE 2018 (LIVE WITH PIANO) [BIXRHtSLBic].mp3
/home/pi/MediaFolder/mp3/Youtube/Sefa @ Reverze 2022 [REUPLOAD] [-5ZgWmSqGdo].mp3
/home/pi/MediaFolder/mp3/Youtube/Sefa Defqon.1 Theatre 2023 FULL [D_jG6CHl1NY].mp3
/home/pi/MediaFolder/mp3/Youtube/Sefa Defqon 1 theatre - full set [YQr2iA8vcjA].mp3
/home/pi/MediaFolder/mp3/Youtube/Sefa Defqon.1 Weekend Festival 2019 [m9bRC92OsfI].mp3
/home/pi/MediaFolder/mp3/Youtube/Shinzou Wo Sasageyo (Attack On Titan) - Metal Cover Feat. Rob Lundgren! [Mo_Y5XZPGgc].mp3
/home/pi/MediaFolder/mp3/Youtube/Sweet but Psycho - Ava Max (Metal Cover) [ckswcYvfeFg].mp3
/home/pi/MediaFolder/mp3/Youtube/FiNCH x PAUL ELSTAK - GABBER GIRL (prod. Paul Elstak, Dasmo & Mania Music) [Official Video] 4k [3smGQOexuSU].mp3
/home/pi/MediaFolder/mp3/Youtube/Frenchcore Familia I Defqon.1 Weekend Festival 2023 I Thursday I BLACK [i_MZvopQHE8].mp3
/home/pi/MediaFolder/mp3/Youtube/Frenchcore Mix 2023 #11 [ZOz3Ph3WZdY].mp3
/home/pi/MediaFolder/mp3/Youtube/GPF & J1zzy - King Of The Pieps (Official Video) [F5B84XsUYJ8].mp3
/home/pi/MediaFolder/mp3/Youtube/If BLACK SABBATH wrote 'JOLENE' [YRAheVxhuIA].mp3
/home/pi/MediaFolder/mp3/Youtube/If Rammstein wrote 'Every Breath You Take' [_j9Vm3t1HHI].mp3
/home/pi/MediaFolder/mp3/Youtube/If Rammstein wrote 'Poison' [bNStVF7SsTE].mp3
/home/pi/MediaFolder/mp3/Youtube/If Rammstein wrote 'You Spin Me Round' [6ufauqY2Rn4].mp3
/home/pi/MediaFolder/mp3/Youtube/If Sepultura wrote 'Whenever, Wherever' [GvMrxnQg1hI].mp3
/home/pi/MediaFolder/mp3/Youtube/If SLAYER wrote 'JUMP' [E_pj1LWBZZA].mp3
/home/pi/MediaFolder/mp3/Youtube/If SLAYER wrote 'SWEET DREAMS' [tz8VNzX_IHs].mp3
/home/pi/MediaFolder/mp3/Youtube/If System Of A Down wrote 'Livin' La Vida Loca' [bsxQ6MN4mrA].mp3
/home/pi/MediaFolder/mp3/Youtube/Jak się myje kibel Epic Viking Folk [EYFOzJZsO3A].mp3
/home/pi/MediaFolder/mp3/Youtube/JAM Project - THE HERO !! (One Punch Man OP)┃Raon Lee x PelleK [5u-1VVWM9l0].mp3
/home/pi/MediaFolder/mp3/Youtube/JKLL & Dr. Peacock ft. Ellene Masri - Hit The Road Jack [Mt6nfbeRpe8].mp3
/home/pi/MediaFolder/mp3/Youtube/Koncert ADU na ŚDM w Krakowie - Jaraj się Marią [xkOQds-lQDk].mp3
/home/pi/MediaFolder/mp3/Youtube/KUPOWANIE BILETU NA MECZ LIGI MISTRZÓW ALE TO EUROBEAT [zM2X0a_z6a8].mp3
/home/pi/MediaFolder/mp3/Youtube/LET 3 - Mama ŠČ! Official video Eurovision 2023 [O_tmsim6lPY].mp3
/home/pi/MediaFolder/mp3/Youtube/Linked Horizon - Shinzo wo Sasageyo! (LIVE) Attack on Titan Opening 3 [2YNQYYHT8Uc].mp3
/home/pi/MediaFolder/mp3/Youtube/Linked Horizon Attack on Titan OPENINGS LIVE [FhM402sKgqA].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx - Tree of Life (Psy to Hard)[Official video] ☯️ [HM-zIwaZr1A].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx Dominator Festival 2022 - Hell of a Ride [5Y6PUQcD5hU].mp3
/home/pi/MediaFolder/mp3/Youtube/BRING ME THE HORIZON ⧸⧸ KINGSLAYER ft. BABYMETAL 【NEX_FEST】 [pAM8MQt6I6I].mp3
/home/pi/MediaFolder/mp3/Youtube/BWSP Fałszywy Raszyn [EKHSkMYhgkY].mp3
/home/pi/MediaFolder/mp3/Youtube/DARK TECHNO MIX Andrea Botez [4K] [M_aOXL5Sg4I].mp3
/home/pi/MediaFolder/mp3/Youtube/dArtagnan - Farewell ft. Patty Gurdy [ckSEnb_I3Zg].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 2018 Sefa [-sfrrxEW158].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Legends 2023 Sunday [JuyNNkxbbFA].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2018 POWER HOUR [QdGz0OHQ9S8].mp3
/home/pi/MediaFolder/mp3/Youtube/Defqon.1 Weekend Festival 2019 POWER HOUR [vJ2eHsQv7Ac].mp3
/home/pi/MediaFolder/mp3/Youtube/DJ AniMe - Hard Techno Hardcore Mix [B2KuebFsfN4].mp3
/home/pi/MediaFolder/mp3/Youtube/Syndicate 2023 D-Fence vs AniMe [oLAOmeoI2Dc].mp3
/home/pi/MediaFolder/mp3/Youtube/Syntetic - Nagi Szopen [tXcUOUZqX1Y].mp3
/home/pi/MediaFolder/mp3/Youtube/The Hero ONE-PUNCH MAN (Full) feat. Angelo Bissanti ワンパンマン [NSG32WJX6-c].mp3
/home/pi/MediaFolder/mp3/Youtube/The Syntetic - Człowiek Widmo [yS0Lv2Pv99g].mp3
/home/pi/MediaFolder/mp3/Youtube/The Syntetic - Hollywood [3Psr2H9A90A].mp3
/home/pi/MediaFolder/mp3/Youtube/The Syntetic - Kleopatra [Jtf6q7_LX_Y].mp3
/home/pi/MediaFolder/mp3/Youtube/The Syntetic - Niewidzialny Templariusz [DlzNRywOe9Q].mp3
/home/pi/MediaFolder/mp3/Youtube/This Is Sefa Defqon.1 2022 [5mEWXmS3cnM].mp3
/home/pi/MediaFolder/mp3/Youtube/This Is Sefa The Spotlight Defqon.1 2024 [TR7mmkZuIuk].mp3
/home/pi/MediaFolder/mp3/Youtube/Thunderdome 2023 Dr. Peacock [7kZCTY77K9k].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon Amarth - Raise Your Horns (Official Video) [Ndu33Uv7Aco].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon Amarth - Raven's Flight [H24S0nym-pE].mp3
/home/pi/MediaFolder/mp3/Youtube/AMON AMARTH- Raise Your Horns ( Live 2016 ) [KwEJWrx8bLg].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon amarth-Raise your horns live (Hellfest) 2016 [voGBBSw_fFo].mp3
/home/pi/MediaFolder/mp3/Youtube/Anime - Imagination Festival Hardcore [SWgZ9YPwhhM].mp3
/home/pi/MediaFolder/mp3/Youtube/AniMe @ Dominator Festival 2023 - Voyage of the Damned [caCjlVO7ZGA].mp3
/home/pi/MediaFolder/mp3/Youtube/AniMe @ Masters of Hardcore 2022 - Magnum Opus [NHc4Lne0mFA].mp3
/home/pi/MediaFolder/mp3/Youtube/AniMe BLACK SUGAR 2022 EQ Music Poland [H4jHMo1EB34].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Sensualna ( cover Sexualna Mirami) [519hvggfQtM].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Zabierz mnie do Arsenału [kX2W6t-z7xo].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - CHILDREN OF THE INTERNET [do7jTWPpn2c].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - Church is a girl [evdx4YdCv6I].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - Hej husarzu! NIE_PODLE_głości dzień [SReTynvd6ek].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - HOUSTON, HOUSTON [C9Vlw4jB7iM].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - Na Święta chcę Ciebie (Wędrowcu w potrzebie) [IMwMUr2NvSg].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - niUNIA EUROPEJSKA [itrYkDzdAkw].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU Ada Karczmarczyk - RODZINA TO... [R2mmHMembrg].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU feat MATEJKO - Nie strzelam do zdrajców oczami [PGL6Q9G4_JM].mp3
/home/pi/MediaFolder/mp3/Youtube/All Time Low - Kids In The Dark (Official Music Video) [SaIegdJxTsE].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon Amarth - Raise Your Horns #Woodstock2017 [YCDkAT6671c].mp3
/home/pi/MediaFolder/mp3/Youtube/Amon Amarth - Raise Your Horns (Live At Summer Breeze) [jVOluNDjc5s].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Idź do światła i nie pierdol! [13e4n5UxylU].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Intronizacja Chrystusa na Króla w korporacjach [pVyBe-FdTDk].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - JARAJ SIĘ MARIĄ [7EzpQoDfVyo].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - JP2 in da house [cOZZa7ycovY].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Lecimy ze Smoleńska z powrotem [f3CVfG4pV8M].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Na Tinderze w dobrej wierze [QuWYrH8knzk].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Nie chcę w lewo, nie chcę w prawo [J3Ok-KcbQ80].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Niszcz szatana Łaską Pana [LNyC6YA8NO8].mp3
/home/pi/MediaFolder/mp3/Youtube/ADU - Oddam ciało, oddam duszę (by już nie być prekariuszem) [4LjmMj3Gyyo].mp3
/home/pi/MediaFolder/mp3/Youtube/Van Halen Ain't Talkin' 'Bout Love 1986 [b1NmPFgdt6Y].mp3
/home/pi/MediaFolder/mp3/Youtube/We Must Fight - President Reagan (Long Version) [JDVT-8tUfiE].mp3
/home/pi/MediaFolder/mp3/Youtube/Występ ADU na THE ARTISTS 2015 - God is the biggest director [Rkp6QaDdO6A].mp3
/home/pi/MediaFolder/mp3/Youtube/Yousei Teikoku - Patriot Anthem live HQ Sub Engita [HK3ZN5bpr-M].mp3
/home/pi/MediaFolder/mp3/Youtube/[Official Video] JAM Project - THE HERO !! - 2015.11.29 in Yokohama Arena - One Punch Man [NL-iKNk1FyU].mp3
/home/pi/MediaFolder/mp3/Youtube/[Official Video] Yousei Teikoku - Astral Dogma - 妖精帝國 [_EeYxtAeaX4].mp3
/home/pi/MediaFolder/mp3/Youtube/[Official Video] Yousei Teikoku - Kuusou Mesorogiwi - 空想メソロギヰ 妖精帝國 [ZZvJY7_gyfw].mp3
/home/pi/MediaFolder/mp3/Youtube/「Nightcore Empyre One Hands Up Mix」 [PUh8uiR7Dao].mp3
/home/pi/MediaFolder/mp3/Youtube/和楽器バンド 千本桜 [K_xTet06SUo].mp3
/home/pi/MediaFolder/mp3/Youtube/💛🤍"Barka - Mała Armia Janosika w Watykanie🎻(150 .górali gra dla Jana Pawła II w dniu Jego urodzin) [NaRRlqd-uaE].mp3
/home/pi/MediaFolder/mp3/Youtube/Barka - Agnieszka Cudzich (live) [e74D5FmtXow].mp3
/home/pi/MediaFolder/mp3/Youtube/New Kids Feat. Paul Elstak - Turbo (Official German Video HD) [HKF4hobJl2A].mp3
/home/pi/MediaFolder/mp3/Youtube/OBERSCHLESIEN - Król Olch [OFFICIAL VIDEO] [KPJPJzpk_QQ].mp3
/home/pi/MediaFolder/mp3/Youtube/One Punch Man FULL ENGLISH OPENING (The Hero - Jam Project) Cover by Jonathan Young [XMCYNH1EJTg].mp3
/home/pi/MediaFolder/mp3/Youtube/Orkiestra online #wdomuzagrane - Co mi Panie dasz (arr. Adam Sztaba) [7NSXXttiwHw].mp3
/home/pi/MediaFolder/mp3/Youtube/Paul Elstak - Full set - Intents Festival 2024 [WVzwkPDiLTc].mp3
/home/pi/MediaFolder/mp3/Youtube/Paul Elstak x GPF x Boogshe - Vet En Hard (Official Video) [5xVx127afSA].mp3
/home/pi/MediaFolder/mp3/Youtube/Peacock in Concert - Mad Masquerade Show 2023 Silverdome Zoetermeer NL [OWM8dP1WbUk].mp3
/home/pi/MediaFolder/mp3/Youtube/POWER HOUR 2022 Defqon.1 Weekend Festival Sixty minutes of pure insanity [fX1kUoeUhPg].mp3
/home/pi/MediaFolder/mp3/Youtube/POWER HOUR 2023 Defqon.1 Weekend Festival This is Madness [A7thBilOLFU].mp3
/home/pi/MediaFolder/mp3/Youtube/Power Hour Six Years of Insanity Defqon.1 at Home 2020 [HiMTwi3_09U].mp3
/home/pi/MediaFolder/mp3/Youtube/Q-dance Presents The Hardstyle Top 40 September 2024 [aTAvXvfw-pg].mp3
/home/pi/MediaFolder/mp3/Youtube/Reverze 2024 Dr. Peacock [L6nKIyiCmLA].mp3
/home/pi/MediaFolder/mp3/Youtube/Barka (Electro Remix) [WQsaVznexqw].mp3
/home/pi/MediaFolder/mp3/Youtube/Barka - ukochana pieśń Jana Pawła II [0qzLRlQFFQ4].mp3
/home/pi/MediaFolder/mp3/Youtube/Best Of Globus Epic Vocal Rock Orchestral [FS0Csetvl4M].mp3
/home/pi/MediaFolder/mp3/Youtube/best summer song 2024 Hardstyle Remix Best Hardstyle Remixes Of Popular Songs 2024 [9oGZ9fCW8FM].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx & Neika - Chichovite (Frenchcore to Hardtek)[Official video]☯️ [EGDwQbXBpZc].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx & Otyken - My wing (Rave music edit) [ylUsbg-yUZ8].mp3
/home/pi/MediaFolder/mp3/Youtube/Billx & Vandal - Rolling Paper Hard edit free remix (Official video) [fi7U24itRaQ].mp3
/home/pi/MediaFolder/mp3/Youtube/Electric Callboy - Live @ Rock am Ring 2024 #RAR2024 [jQN23aw8oaI].mp3
/home/pi/MediaFolder/mp3/Youtube/Electric Callboy - We Got the Moves #polandrock2024 [KNyQP5ql6pY].mp3
/home/pi/MediaFolder/mp3/Youtube/ELECTRIC CALLBOY ft BABYMETAL - RATATATA (Live at Resurrection Fest EG 2024) [R78nx63OfPg].mp3
/home/pi/MediaFolder/mp3/Youtube/ELYOSE - Les artisans du chaosDe guerre lasse (Live at the Halloween Horror Night 2016, Paris) [Bf_XofH9j0E].mp3
/home/pi/MediaFolder/mp3/Youtube/Eurodance & Bubblegum EDM Mix Tinzo [zvXAt1uB6ME].mp3
-191
View File
@@ -1,191 +0,0 @@
# FILEPATH: /home/mtuszowski/conjurer/conjurer_musician/radio_conjurer.liq
# This script sets up a Liquidsoap radio stream with various features and configurations.
# Load icecast credentials from a JSON file
let json.parse credentials = file.contents("/home/pi/Conjurer/icecast_credentials.json")
# Enable replaygain metadata processing
enable_replaygain_metadata()
# Set up a playlog for tracking played tracks
l = playlog(duration = 72000.0, persistency="/home/pi/Conjurer/persistence.log")
# Function to check if a track can be played based on its metadata
def check(r)
m = request.metadata(r)
if l.last(m) < 36000. then
log.info("Rejecting #{m['filename']} (played #{l.last(m)}s ago).")
false
else
l.add(m)
true
end
end
# Define playlists to be used in the stream
s1 = replaygain(playlist(reload_mode="watch", check_next=check, "/home/pi/Conjurer/all_playlist.playlist"))
s2 = replaygain(playlist(reload_mode="watch", check_next=check, "/home/pi/Conjurer/priority_queue.playlist"))
s3 = replaygain(playlist(reload_mode="watch", check_next=check, "/home/pi/Conjurer/hit.playlist"))
# Create a request queue for user-generated requests
requests_queue = request.queue()
# Function to process the request queue and add new requests
def queue_processing()
text=file.lines("/home/pi/Conjurer/request.playlist")
if text != [] then
list.iter(fun(item) -> requests_queue.push.uri(item), text)
file.remove("/home/pi/Conjurer/request.playlist")
f = file.open("/home/pi/Conjurer/request.playlist", create=true)
f.close()
end
end
# Configure output formats and destinations
def now_playing(m)
# raw lookup ("" if missing)
raw_title = m["title"]
raw_artist = m["artist"]
# default if empty
title = if raw_title == "" then "Unknown" else raw_title end
artist = if raw_artist == "" then "Unknown" else raw_artist end
log.critical("Now playing #{artist} - #{title}")
# write it out
system("echo '#{artist} - #{title}' > /tmp/now_playing.txt")
m
end
# Randomly select a playlist with weights
s4 = random(id="randomizer", weights=[2, 3, 5], [s1, s2, s3])
# Load jingles playlist
jingles = (playlist(reload_mode="watch", "/home/pi/Conjurer/jingles.playlist"))
# Create the main stream with random playlist and jingles
s = rotate(id="randomizer", weights=[10, 1], [s4, jingles])
s = crossfade(fade_out=2., fade_in=2., duration=4., fallback(id="switcher", track_sensitive=true, [requests_queue, s]))
s = metadata.map(now_playing, s)
# Set up an interactive harbor for controlling the stream
interactive.harbor(port = 9999)
# Set up interactive controls for bass boost
f = interactive.float("f", description="Frequency", min=0., max=1000., unit="Hz", 200.)
g = interactive.float("g", description="Gain", min=0., max=20., unit="dB", 8.)
b = bass_boost(frequency=f, gain=g, s)
s = add([s, b])
# Set up interactive control for main volume
a = interactive.float("main_volume", min=0., max=20., 1.1)
s = compress.multiband.interactive(bands=7, s)
mic_gain = interactive.float("mic_volume", min=0., max=120., 0.5)
# Apply audio processing effects
tmic = buffer(input.pulseaudio()) # Microphone
mic = amplify(mic_gain, tmic)
mic = gate(threshold=-80., range=-120., mic)
mic = compress(threshold=0., ratio=2.,mic)
mic = nrj(normalize(mic))
mic = blank.strip(max_blank=15., min_noise=.1, threshold=-30., mic)
mic = fallback(id="switcher2", track_sensitive=false, [mic, blank()])
# Apply audio processing effects
s = nrj(s)
s = amplify(a, s)
# Skip blank sections in the stream
s = blank.skip(max_blank=10., s)
#Manual audition override
live_enabled = interactive.bool("Going Live!", true)
s = add([mic,s])
s=switch(track_sensitive=true,
[(live_enabled, mic),
({true}, s)])
# Configure logging settings
log_to_stdout = true
log_to_file = true
logpath = "/home/pi/Conjurer/radio_log.log"
loglevel = 3
set("log.stdout", log_to_stdout)
set("log.level", loglevel)
# Enable logging to file
set("log.file", log_to_file)
set("log.file.path", logpath)
# Set up emergency fallback track
emergency = single("/home/pi/MediaFolder/mp3/Youtube/Dr. Peacock - Trip to Ireland [GvrvQTUbUcA].mp3")
radio = fallback(id="switcher2", track_sensitive=false, [s, emergency])
# Set up an interactive control for skipping tracks
p = interactive.bool("Skip track", false)
def http_skip(~protocol, ~data, ~headers, uri)=
radio.skip()
http.response(code=200,data="Skipped")
end
harbor.http.register(port=54321,method="GET","/skip", http_skip)
# Function to process the request queue and skip the current track if requested
def check_skip()
if p() then
log.info("Skipping current track.")
radio.skip()
p.set(false)
end
end
# Run the queue processing function every 60 seconds
thread.run(every=60., queue_processing)
# Run the check_skip function every 5 seconds
thread.run(every=15., check_skip)
# Enable persistent script parameters
interactive.persistent("script.params")
# Configure output formats and destinations
output.icecast(%mp3, host="radio", port=8000, password=credentials.password, icy_metadata="true", mount="mp3-stream", radio)
output.pulseaudio(radio)
#output.file.hls("/tmp/hls", [("mp3-low", %mp3(bitrate=96)), ("mp3-hi", %mp3(bitrate=160))], radio)
# Uncomment the following lines to enable additional output formats
# output.icecast(%opus, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="opus-stream", radio)
# output.icecast(%ogg, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="ogg-stream", radio)
# output.icecast(%aac, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="aac-stream", radio)
# output.icecast(%flac, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="flac-stream", radio)
# output.icecast(%vorbis, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="vorbis-stream", radio)
# output.icecast(%speex, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="speex-stream", radio)
# output.icecast(%wav, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="wav-stream", radio)
# output.icecast(%pcm, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="pcm-stream", radio)
# output.icecast(%raw, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="raw-stream", radio)
# output.icecast(%s16l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s16l-stream", radio)
# output.icecast(%s16b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s16b-stream", radio)
# output.icecast(%s24l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s24l-stream", radio)
# output.icecast(%s24b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s24b-stream", radio)
# output.icecast(%s32l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s32l-stream", radio)
# output.icecast(%s32b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s32b-stream", radio)
# output.icecast(%s64l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s64l-stream", radio)
# output.icecast(%s64b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s64b-stream", radio)
# output.icecast(%s128l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s128l-stream", radio)
# output.icecast(%s128b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s128b-stream", radio)
# output.icecast(%s256l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s256l-stream", radio)
# output.icecast(%s256b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s256b-stream", radio)
# output.icecast(%s512l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s512l-stream", radio)
# output.icecast(%s512b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s512b-stream", radio)
# output.icecast(%s1024l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s1024l-stream", radio)
# output.icecast(%s1024b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s1024b-stream", radio)
# output.icecast(%s2048l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s2048l-stream", radio)
# output.icecast(%s2048b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s2048b-stream", radio)
# output.icecast(%s4096l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s4096l-stream", radio)
# output.icecast(%s4096b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s4096b-stream", radio)
# output.icecast(%s8192l, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s8192l-stream", radio)
# output.icecast(%s8192b, host="retropie", port=8000, password=credentials.password, icy_metadata="true", mount="s8192b-stream", radio)
@@ -1,4 +0,0 @@
flask
waitress
sshtunnel
requests
-195
View File
@@ -1,195 +0,0 @@
{
"string": [],
"bool": [ [ "Skip track", false ], [ "Going Live!", false ] ],
"int": [],
"float": [
[
"mic_volume",
0.0
],
[
"compress_gain6",
0.1
],
[
"compress_ratio6",
7.9
],
[
"compress_threshold6",
-15.8
],
[
"compress_release6",
30.0
],
[
"compress_attack6",
30.0
],
[
"compress_frequency6",
18610.0
],
[
"compress_gain5",
5.4
],
[
"compress_ratio5",
4.8
],
[
"compress_threshold5",
-13.6
],
[
"compress_release5",
120.0
],
[
"compress_attack5",
160.0
],
[
"compress_frequency5",
13950.0
],
[
"compress_gain4",
6.5
],
[
"compress_ratio4",
4.0
],
[
"compress_threshold4",
-12.2
],
[
"compress_release4",
130.0
],
[
"compress_attack4",
200.0
],
[
"compress_frequency4",
3890.0
],
[
"compress_gain3",
5.5
],
[
"compress_ratio3",
3.5
],
[
"compress_threshold3",
-11.7
],
[
"compress_release3",
140.0
],
[
"compress_attack3",
250.0
],
[
"compress_frequency3",
2270.0
],
[
"compress_gain2",
3.3
],
[
"compress_ratio2",
3.9
],
[
"compress_threshold2",
-11.5
],
[
"compress_release2",
120.0
],
[
"compress_attack2",
250.0
],
[
"compress_frequency2",
1920.0
],
[
"compress_gain1",
5.6
],
[
"compress_ratio1",
3.4
],
[
"compress_threshold1",
-12.2
],
[
"compress_release1",
120.0
],
[
"compress_attack1",
220.0
],
[
"compress_frequency1",
650.0
],
[
"compress_gain0",
7.5
],
[
"compress_ratio0",
3.2
],
[
"compress_threshold0",
-13.1
],
[
"compress_release0",
110.0
],
[
"compress_attack0",
140.0
],
[
"compress_frequency0",
110.0
],
[
"compress_wet",
1.0
],
[
"main_volume",
1.8
],
[
"g",
1.0
],
[
"f",
106.4
]
]
}
-9
View File
@@ -1,9 +0,0 @@
<html>
<head>
<title>HTTP Live Streaming Example</title>
</head>
<body>
<video src="/tmp/hls/stream.m3u8" height="300" width="400">
</video>
</body>
</html>
-24
View File
@@ -1,24 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>
-38
View File
@@ -1,38 +0,0 @@
[
[
"Hammer oparzy\u0142 si\u0119 do II/III stopnia prodi\u017cem",
"2023-05-29 14:00:19.00000"
],
[
"Pat wy\u0142\u0105czy\u0142\u0105 wydruk i wywo\u0142a\u0142a spi\u0119cie na p\u0142ycie g\u0142\u00f3wnej",
"2023-06-01 15:27:43.444444"
],
[
"Pat zala\u0142a \u0142azienk\u0119",
"2023-06-07 20:40:43.453654"
],
[
"Pat przyjeba\u0142a g\u0142ow\u0105 oraz barkiem w drzwi od szafki",
"2023-06-07 22:40:43.453654"
],
[
"Pat oparzy\u0142a si\u0119 kawiark\u0105",
"2023-06-08 11:11:43.453654"
],
[
"Hammer rozci\u0105\u0142 palec trzepi\u0105c przez balkon jeleni\u0105 sk\u00f3r\u0119",
"2023-06-08 18:10:43.453654"
],
[
"Pat zgubi\u0142a w zamkni\u0119tym pomieszczeniu spr\u0119\u017cyn\u0119 od kuchenki gazowej",
"2023-06-08 23:29:43.453654"
],
[
"Hammer kupi\u0142 Je\u017cowi bilet na 16 zamiast na 09 czerwca",
"2023-06-09 14:52:43.453654"
],
[
" Z\u0142ama\u0142 paznokie\u0107 otwierajac piwo",
"2023-06-21 21:37:54.583469"
]
]
-263
View File
@@ -1,263 +0,0 @@
import json
import logging
import os
import random
import re
import shutil
from datetime import datetime
import discord
import numpy as np
from discord.ext import commands, tasks
from ai_functions import get_random_cyclic_message
from constants import (
ENCODING,
LAST_SPONTANEOUS_CALL,
LOGFILE,
LOGSTORE,
MEMORY_FIVE_MUZYKA,
MEMORY_FIVE_SIARA,
TIME_BETWEEN_CALLS,
)
class AdministrationModule(commands.Cog):
def __init__(self, bot, logger_name):
self.bot = bot
self.logger = logging.getLogger(logger_name)
@commands.hybrid_command(
name="galeria_slaw",
description="Jeśli nie wiesz jak użyć tej komendy to nawet nie próbuj",
guild=discord.Object(id=664789470779932693),
)
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
async def galeria_slaw(self, ctx):
if isinstance(ctx.channel, discord.DMChannel):
for guild in self.bot.guilds:
async for entry in guild.bans(limit=1500):
fnord = discord.File(
"/home/pi/Conjurer/niech_spierdala.png",
spoiler=False,
description="Niech spierdala",
)
await ctx.reply(
f"User: {entry.user} wyjebany z serwera {guild.name} za {entry.reason} ",
file=fnord,
)
@commands.hybrid_command(
name="update_banlist",
description="Jeśli nie wiesz jak użyć tej komendy to nawet nie próbuj",
guild=discord.Object(id=664789470779932693),
)
@commands.has_any_role('Jarl', 'Thane')
async def update_banlist(self, ctx):
"""
Update a banlist in a Discord guild from preprovided list in channel.
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
contains information about the context in which the command was invoked, such as the message, the
channel, the server, and the user who invoked the command. This information can be used to perform
various actions, such
"""
async with ctx.channel.typing():
allowed = False
for role in ctx.author.roles:
if role.name == "Jarl":
allowed = True
if ctx.channel.id != 1102190666827702342:
# trunk-ignore(codespell/misspelled)
await ctx.send("Nie wydaje mnie sie")
elif not allowed:
await ctx.send("Idź bo Cię zdziele")
else:
tobancunter = 0
async with ctx.typing():
# 1. get list of users posted on channel for banning
channel = ctx.channel
messages = [
message async for message in channel.history(limit=None)
]
ids_to_ban = []
for message in messages:
lines = message.content.split("\n")
for line in lines:
match = re.search(
"\\d{18}",
line,
# trunk-ignore(codespell/misspelled)
) # poprawilem backslash na podwojny bo linter sie czepial
if match:
ids_to_ban.append(match.group())
tobancunter += 1
# 2. get list of already banned users for all servers Conjurer
# has rights to
for guild in self.bot.guilds:
bancunter = 0
# trunk-ignore(codespell/misspelled)
self.logger.info("Serwer: %s", guild)
current_banlist = []
permission = True
try:
async for entry in guild.bans(limit=None):
current_banlist.append(entry.user.id)
bancunter += 1
except BaseException: # pylint: disable=broad-exception-caught
permission = False
if permission:
# 3. compare lists ban only users on list 2 and not on
# list 1
cunter_counter = 0
bad_id_cunter_counter = 0
ban_list = np.setdiff1d(ids_to_ban, current_banlist)
for ident in ban_list:
try:
tmp_user = await self.bot.fetch_user(int(ident))
await guild.ban(
tmp_user,
reason="Automatyczna lista banów",
delete_message_seconds=0,
)
# TODO: Maybe use guild.bulk_ban ?
cunter_counter += 1
except discord.NotFound:
self.logger.info(
"Znaleziono uzyszkodnika ktory juz nie ma konta"
)
bad_id_cunter_counter += 1
# 4. return message success/failure - how many banned
await ctx.send(
"Obecnie na serwerze {guild} jest {bancunter} zbanowanych użytkowników. Znaleziono na tym kanale {tobancunter} id użytkowników do zbanowania. Zbanowano {cunter_counter} użytkowników. Na liście jest {bad_id_cunter_counter} użytkowników którzy skasowali już konto"
)
else:
await ctx.send(
f"Nie mam na serwerze {guild} uprawnień do banowania. :()"
)
await ctx.send("Zrobione tak czy inaczej")
@commands.hybrid_command(
name="archive_channel",
description="Jeśli nie wiesz jak użyć tej komendy to nawet nie próbuj",
guild=discord.Object(id=664789470779932693),
)
@commands.has_any_role('Jarl', 'Thane')
async def archive_channel(self, channel_no):
"""
The function `archive_channel` retrieves messages from a specified channel, processes them, and
saves the data in a JSON file with a timestamp in the filename.
:param channel_no: The `archive_channel` function you provided seems to be incomplete. It looks like
you are trying to archive messages from a Discord channel into a JSON file
"""
channel = self.bot.get_channel(channel_no)
messages = [message async for message in channel.history(limit=None)]
path_newfile = f"{LOGSTORE}channeldump_{channel_no}_{datetime.now()}.json"
new_data = []
for message in messages:
new_data.append(message)
with open(path_newfile, "x", encoding=ENCODING) as new_file:
new_file.seek(0)
json.dump(new_data, new_file, indent=4)
@tasks.loop(seconds=120)
async def check_self(self):
"""
The function `check_data` periodically checks for conditions to send messages and manage log files
in a Discord channel.
"""
# logger.info("Heartbeat of cleanup proc")
channel = self.bot.get_channel(1062047367337095268)
messages = [message async for message in channel.history(limit=1)]
for mess in messages:
channel = mess.channel
if os.path.getsize(LOGFILE) > 60000000:
await channel.send(
"*Conjurer porządkuje bar, wypala szklanki do czysta miotaczem płomieni ze swojej zbroi i ogólnie wygląda na zajętego....*"
)
async with channel.typing():
shutil.copyfile(LOGFILE, f"{LOGSTORE}discord{datetime.now()}")
self.logger.info("Log rollover")
handlers = self.logger.handlers
for handler in handlers:
if isinstance(handler, logging.handlers.RotatingFileHandler):
handler.doRollover()
await channel.send(
"*Przeciąga się za barem* No dobra - porobione to można dalej pi... *Zauważa spojrzenie Hammera* ...sać powieści o naszym wspaniałym barze SZEFIE!"
)
if os.path.getsize(MEMORY_FIVE_MUZYKA) > 3000000:
await channel.send(
"*Conjurer porządkuje bar, wypala szklanki do czysta miotaczem płomieni ze swojej zbroi i ogólnie wygląda na zajętego....*"
)
async with channel.typing():
path_newfile = f"{LOGSTORE}pamiec_muzyki{datetime.now()}.json"
self.logger.info(path_newfile)
with open(
MEMORY_FIVE_MUZYKA, "r+", encoding=ENCODING
) as file_music_memory:
with open(path_newfile, "x", encoding=ENCODING) as new_file:
# First we load existing data into a dict.
file_data = json.load(file_music_memory)
new_data = []
new_data.append(file_data[0])
new_data.extend(file_data[:-20])
file_music_memory.truncate(0)
file_music_memory.seek(0)
# convert back to json.
new_file.seek(0)
json.dump(new_data, file_music_memory, indent=4)
json.dump(file_data, new_file, indent=4)
await channel.send(
"*Przeciąga się za barem* No dobra - porobione to można dalej pi... *Zauważa spojrzenie Hammera* ...sać powieści o naszym wspaniałym barze SZEFIE!"
)
if os.path.getsize(MEMORY_FIVE_SIARA) > 3000000:
path_newfile = f"{LOGSTORE}pamiec_rozmow{datetime.now()}.json"
self.logger.info(path_newfile)
await channel.send(
"*Conjurer porządkuje bar, ścina lekkim laserem pulsacyjnym powierzchnie baru o grubości kilku mikronów i ogólnie wygląda na zajętego....*"
)
with open(MEMORY_FIVE_SIARA, "r+", encoding=ENCODING) as file:
with open(path_newfile, "x", encoding=ENCODING) as new_file:
# First we load existing data into a dict.
file_data = json.load(file)
new_data = []
new_data.append(file_data[0])
new_data.extend(file_data[-20])
file.truncate(0)
file.seek(0)
new_file.seek(0)
# convert back to json.
json.dump(new_data, file, indent=4)
json.dump(file_data, new_file, indent=4)
await channel.send(
"*Przeciąga się za barem* No dobra - porobione to można dalej pi... *Zauważa spojrzenie Hammera* eprzyć o głupotach z klientami... Szefie... *Bierze 'ukradkowy' łyk z piersiówki*"
)
global LAST_SPONTANEOUS_CALL
global TIME_BETWEEN_CALLS
tdelta = datetime.now() - LAST_SPONTANEOUS_CALL
tdelta = tdelta.total_seconds()
if tdelta > TIME_BETWEEN_CALLS:
self.logger.info("Spontaneous call")
# trunk-ignore(bandit/B311)
TIME_BETWEEN_CALLS = random.randint(
10200, 272800
) # temp random, set after each call
self.logger.debug(TIME_BETWEEN_CALLS)
LAST_SPONTANEOUS_CALL = datetime.now()
async with channel.typing():
message = await get_random_cyclic_message(self.bot)
self.logger.info("Odpowiedz")
self.logger.info(message)
await channel.send(message)
async def setup(bot):
logger = logging.getLogger("discord")
am = AdministrationModule(bot, "discord")
await bot.add_cog(am)
am.check_self.start()
logger.info("Loading administration commands module done")
-403
View File
@@ -1,403 +0,0 @@
# ai command cogs
import logging
import re
import sys
from datetime import datetime
from enum import Enum
from typing import Optional
from pathlib import Path
import discord
import openai
import requests
from discord.ext import commands
from other_functions import discord_friendly_send, discord_friendly_reply
import ai_functions
from constants import (
ASSISTANTS,
DATA,
GRAPHICS_PATH,
INITIAL_TIME_WAIT,
MASTER_TIMEOUT,
MESSAGE_TABLE,
OPENAICLIENT,
SPECJALNE_ZIEMNIACZKI,
WORD_REACTIONS,
)
class Dm_Mode(Enum):
ARMIA_HAMMERA = (1,)
SPECJALNY_ZIEMNIACZEK = (2,)
SEKRETNY_SEKSRET = (3,)
ECHO_ECHO = (4,)
class Events(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.logger = logging.getLogger("discord")
self.armia = {}
for superfryta in SPECJALNE_ZIEMNIACZKI.values():
self.armia[superfryta[0]] = Dm_Mode.SPECJALNY_ZIEMNIACZEK
self.logger.info(self.armia)
async def cog_load(self):
self.logger.info("Starting personal assistants")
for superfryta_id, superfryta in SPECJALNE_ZIEMNIACZKI.items():
if superfryta[4] != "":
self.logger.info(
"Personal assistant for user: %s, exists id: %s,name: %s, owner: %s, special instructions: %s assistant id: %s ",
superfryta_id,
superfryta[0],
superfryta[1],
superfryta[2],
superfryta[3],
superfryta[4],
)
thread = await OPENAICLIENT.beta.threads.create()
self.logger.info("Thread id: %s", thread.id)
ASSISTANTS[superfryta[1]] = (
superfryta[2],
superfryta[4],
superfryta[0],
thread,
)
else:
self.logger.info(
"Creating personal assistant for user: %s, id: %s,name: %s, owner: %s, special instructions: %s",
superfryta_id,
superfryta[0],
superfryta[1],
superfryta[2],
superfryta[3],
)
await ai_functions.create_chat_assistant(
superfryta_id, superfryta[0], superfryta[1], superfryta[2], superfryta[3]
)
self.logger.info("Started personal assistants")
@commands.hybrid_command(
name="switch_dm_mode",
description="Jeśli nie wiesz jak użyć tej komendy to nawet nie próbuj",
guild=discord.Object(id=664789470779932693),
)
async def switch_dm_mode(self, ctx, dm_mode_arg: Dm_Mode):
async with ctx.channel.typing():
if isinstance(ctx.channel, discord.DMChannel):
for superfryta in SPECJALNE_ZIEMNIACZKI.values():
self.logger.info(ctx.message.author.id)
self.logger.info(superfryta)
if ctx.message.author.id == superfryta[0]:
self.armia[ctx.message.author.id] = dm_mode_arg
self.logger.info(self.armia)
await ctx.reply("Weszlo")
return
await ctx.reply(
"Tylko członkowie Armii Hammera mogą używać. Nie jesteś jednym z nich"
)
else:
await ctx.reply("Nope. Nie wiesz jak użyć")
@commands.hybrid_command(
name="armia_hammera",
description="Jeśli nie wiesz jak użyć tej komendy to nawet nie próbuj",
)
async def armia_hammera(
self, ctx, message_txt: str, recipient: Optional[discord.User]
):
for superfryta in SPECJALNE_ZIEMNIACZKI.values():
if ctx.message.author.id == superfryta[0]:
await self.armia_hammera_back(ctx, message_txt, recipient)
return
await ctx.reply("Tylko członkowie Armii Hammera mogą używać. Nie jesteś jednym z nich")
async def armia_hammera_back(self, ctx, message_txt, recipient=None):
self.logger.info("Armia Hammera")
recipients = []
if recipient:
recipients.append(recipient.id)
else:
for superfryta in SPECJALNE_ZIEMNIACZKI.values():
recipients.append(superfryta[0])
self.logger.info(recipients)
for item in recipients:
user = await self.bot.fetch_user(item)
channel = await user.create_dm()
self.logger.info(
"User %s -> %s: %s", ctx.message.author, user, message_txt
)
await discord_friendly_send(channel, message_txt)
await discord_friendly_reply(ctx, "Poszło")
#TODO: NOT IMPLEMENTED YET
@commands.Cog.listener(name="dodaj_do_bazy_wiedzy")
async def dodaj_do_bazy_wiedzy(self, ctx):
for superfryta in SPECJALNE_ZIEMNIACZKI.values():
if ctx.message.author.id == superfryta[0]:
#logic here
return
await ctx.reply("Tylko członkowie Armii Hammera mogą używać. Nie jesteś jednym z nich")
#TODO: NOT IMPLEMENTED YET
@commands.Cog.listener(name="listuj_baze_wiedzy")
async def listuj_baze_wiedzy(self, ctx):
for superfryta in SPECJALNE_ZIEMNIACZKI.values():
if ctx.message.author.id == superfryta[0]:
#logic here
return
await ctx.reply("Tylko członkowie Armii Hammera mogą używać. Nie jesteś jednym z nich")
#TODO: NOT IMPLEMENTED YET
@commands.Cog.listener(name="usun_z_bazy_wiedzy")
async def usun_z_bazy_wiedzy(self, ctx):
for superfryta in SPECJALNE_ZIEMNIACZKI.values():
if ctx.message.author.id == superfryta[0]:
#logic here
return
await ctx.reply("Tylko członkowie Armii Hammera mogą używać. Nie jesteś jednym z nich")
#TODO: NOT IMPLEMENTED YET
@commands.Cog.listener(name="przetworz_plik_linia_po_linii")
async def przetworz_plik_linia_po_linii(self, ctx):
for superfryta in SPECJALNE_ZIEMNIACZKI.values():
if ctx.message.author.id == superfryta[0]:
#logic here
return
await ctx.reply("Tylko członkowie Armii Hammera mogą używać. Nie jesteś jednym z nich")
@commands.Cog.listener()
async def on_message(self, message):
"""
Handle incoming messages in a Discord server, perform various
checks and actions based on the content and context of the message, and respond accordingly.
:param message: The message object that is received when a user sends a message in a Discord server
or DM. The code is checking various conditions and performing actions based on the content of the
message and the context in which it was sent. It also includes TODOs for future improvements
:return: The function `on_message` is being returned.
"""
vykidailo = False
channel = None
if message.author == self.bot.user:
return
if isinstance(message.author, discord.Member):
for role in message.author.roles:
if role.name == "Vykidailo":
vykidailo = True
if ("Conjurer Śpij Słodko Aniołku" in message.content) and vykidailo:
sys.exit()
# kanal bez bota
if message.channel.id == 1095985579147141202:
return
# wentylacja
if message.channel.id == 1083804024173764739:
return
# legendy
if message.channel.id == 1084448332841230388:
return
# interrogation booth
if message.channel.id == 1111625221171052595:
return
if isinstance(message.channel, discord.DMChannel):
self.logger.info(message.author.id)
for superfryta in SPECJALNE_ZIEMNIACZKI.values():
self.logger.info(superfryta[0])
if message.author.id == superfryta[0]:
self.logger.info("Specjalny ziemniak")
if self.armia[message.author.id] == Dm_Mode.SPECJALNY_ZIEMNIACZEK:
#await self.bot.process_commands(message)
await ai_functions.chat_with_assistant(message, superfryta[1])
return
elif self.armia[message.author.id] == Dm_Mode.ECHO_ECHO:
await ai_functions.echo(message)
return
elif self.armia[message.author.id] == Dm_Mode.ARMIA_HAMMERA:
self.logger.info("Armia Hammera get context")
ctx = await self.bot.get_context(message)
self.logger.info("Armia Hammera function call")
await self.armia_hammera_back(ctx=ctx, message_txt=message.content)
return
elif self.armia[message.author.id] == Dm_Mode.SEKRETNY_SEKSRET:
pass
else:
await discord_friendly_send(message.channel,"Coś się wyebao. Wołaj Hammera")
return
channel = self.bot.get_channel(1064888712565100614)
await discord_friendly_send(channel, "Słyszałem ja żem że: " + message.content)
return
channel = message.channel
message_content_lower = message.content.lower()
tdelta = datetime.now() - MASTER_TIMEOUT
tdelta = tdelta.total_seconds()
if "opowiedz o fabryczce" in message_content_lower:
await message.reply(DATA["fabryczka"])
if "opowiedz mi o fabryczce" in message_content_lower:
await message.reply(DATA["fabryczka"])
if tdelta > INITIAL_TIME_WAIT:
for word in WORD_REACTIONS:
if re.search(r"\b" + word + r"\b", message_content_lower):
tdelta = datetime.now() - WORD_REACTIONS[word][2]
tdelta = tdelta.total_seconds()
security_clearance = WORD_REACTIONS[word][4]
reaction = WORD_REACTIONS[word][3]
if tdelta > WORD_REACTIONS[word][1]:
# TODO: to zrobic reactiony
self.logger.info("Ping z procedury reakcji")
if reaction:
emoji = self.bot.get_emoji(WORD_REACTIONS[word][0])
await message.add_reaction(emoji)
elif security_clearance and vykidailo:
await message.reply(WORD_REACTIONS[word][0])
elif not security_clearance:
await message.reply(WORD_REACTIONS[word][0])
WORD_REACTIONS[word][2] = datetime.now()
# TODO: drobne literówki, mentiony, spacja przed dwukropkiem. napraw.
kondziu_mentioned = False
for mention in message.mentions:
if mention == self.bot.user:
kondziu_mentioned = True
if kondziu_mentioned or "conjurer:" in message_content_lower:
async with channel.typing():
self.logger.info("Procedura chatu")
message_content_lower = message_content_lower.replace("conjurer: ", "")
if message.author.nick:
username = message.author.nick
else:
username = message.author.name
vykidailo = False
bartender = False
if kondziu_mentioned:
prompt = message.clean_content
else:
prompt = message.content
for role in message.author.roles:
if role.name == "Vykidailo":
vykidailo = True
if role.name == "Bartender":
bartender = True
global MESSAGE_TABLE # pylint: disable=global-statement
result, MESSAGE_TABLE = await ai_functions.handle_response(
prompt,
vykidailo,
bartender,
MESSAGE_TABLE,
username,
"GENERAL",
)
await discord_friendly_reply(message, result)
if "imaginuje sobie:" in message.content:
async with channel.typing():
self.logger.info("Poczatek procedury obrazkowej")
message_content_lower = message_content_lower.replace("imaginuje sobie: ", "")
self.logger.debug("Wywolanie obrazka: %s", message_content_lower)
try:
response = await OPENAICLIENT.images.generate(
model="dall-e-3",
prompt=message.content,
size="1024x1024",
quality="standard",
n=1,
)
except openai.APITimeoutError as e:
# Handle timeout error, e.g. retry or log
await discord_friendly_reply(
message, f"*Kondziu patrzy na terminal, czeka, czeka, czeka,.... Jeszcze chwile czeka Przypierdala w niego pięścią....* Nie mogę się połączyć z Openai spróbuj od nowa. *Na ekranie pojawia się*: {e}"
)
except openai.APIConnectionError as e:
await discord_friendly_reply(
message, f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Nie mogę się połączyć z Openai. *Na ekranie pojawia się*: {e}"
)
except openai.BadRequestError as e:
# Handle invalid request error, e.g. validate parameters or log
if message.author.nick:
username = message.author.nick
else:
username = message.author.name
resp, _ = await ai_functions.handle_response(
f"Wytlumacz jakie sa zasady dotyczące treści które możesz generować używając Dalle. Wytłumacz błąd {e} prostym językiem. Przeproś za nadmierną cenzurę. Wytłumacz co mogło być nie tak w prompcie '{message.content}'",
True,
True,
MESSAGE_TABLE,
username,
"GENERAL",
)
await discord_friendly_reply(
message, f"Sorki, cenzura: {resp}. Jak chcesz to są kanały na nudle #sexy-foteczky i #kanal-do-fapania *Na ekranie pojawia się: {e}"
)
except openai.AuthenticationError as e:
# Handle authentication error, e.g. check credentials or log
await discord_friendly_reply(
message, f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Wołaj szefa - coś się z hasłem zjebało. *Na terminalu pojawia się:* {e}"
)
except openai.PermissionDeniedError as e:
# Handle permission error, e.g. check scope or log
await discord_friendly_reply(
(
message, f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Wołaj szefa - coś się z uprawnieniami zjebało. *Na terminalu pojawia się:* {e}"
)
)
except openai.RateLimitError as e:
await discord_friendly_reply(
message, f"*Kondziu patrzy na terminal* Wołaj szefa. Zapłacić rachunki za AI trzeba. Jak chcesz to się na #zebranie dorzuć. {e}"
)
except openai.APIError as e:
# Handle API error, e.g. retry or log
await discord_friendly_reply(
message, f"*Kondziu nurkuje za bar, terminal wybucha. Przed tobą ląduje pergamin zapisany pięknym gotykiem a na nim*: {e}"
)
if response:
self.logger.info(response)
image_url = response.data[0].url
image_desc = response.data[0].revised_prompt
self.logger.debug("Wynikowy obrazek pod url: %s", image_url)
response = requests.get(image_url, timeout=360)
temp_file_name = message.content + ".png"
temp_file_name = GRAPHICS_PATH + message.content + ".png"
num = 0
while (Path(temp_file_name)).exists():
temp_file_name = GRAPHICS_PATH + message.content + str(num) + ".png"
num += 1
try:
with open(temp_file_name, "wb") as dalle_file:
dalle_file.write(response.content)
except OSError:
temp_file_name = "/home/pi/oserror.png"
with open(temp_file_name, "wb") as dalle_file:
dalle_file.write(response.content)
except FileNotFoundError:
temp_file_name = "/home/pi/fnferror.png"
with open(temp_file_name, "wb") as dalle_file:
dalle_file.write(response.content)
except Exception as e:
self.logger.error("Nieznany błąd: %s", e)
temp_file_name = "/home/pi/error.png"
with open(temp_file_name, "wb") as dalle_file:
dalle_file.write(response.content)
finally:
self.logger.info("Koniec procedury obrazkowej.")
fnord = discord.File(
temp_file_name, spoiler=False, description=message.content
)
#await message.reply(f"{image_desc}", file=fnord)
await discord_friendly_reply(message,f"{image_desc}", file = fnord)
# *=========================================== Define Functions
async def setup(bot):
logger = logging.getLogger("discord")
await bot.add_cog(Events(bot))
logger.info("Loading ai events module done")
-449
View File
@@ -1,449 +0,0 @@
import asyncio
import json
import logging
import random
import openai
import tiktoken
import time
from other_functions import discord_friendly_send
from constants import (
ASSISTANTS,
CYCLIC_WORDS,
ENCODING,
GPT_SETTINGS,
MEMORY_FIVE_MUZYKA,
MEMORY_FIVE_SIARA,
MESSAGE_TABLE,
MESSAGE_TABLE_MUZYKA,
OPENAICLIENT,
SYSTEM_GPT_SETTINGS,
WORD_REACTIONS,
CHEAP_MODEL,
LATEST_MODEL
)
# this do per user
VECTOR_STORE_ID = -1
def select_model(req_type: str, algo: str) -> str:
# Jeżeli jawnie podano algorithm (i nie jest 'auto'/''):
if algo and str(algo).strip().lower() not in ("auto",):
# wyjątek: MUZYKA ma zawsze być tania — nadpisujemy TYLKO jeśli przyszedł domyślny 'gpt-4o'
if req_type == "MUSIC" and algo.strip() in (LATEST_MODEL,):
return CHEAP_MODEL
return algo
# Auto-dobór:
if req_type == "MUSIC":
return CHEAP_MODEL
return LATEST_MODEL
async def openai_call(messages, model, temperature=0.2):
"""
Responses API dla 4o/4.1*, fallback Chat Completions dla gpt-3.5-turbo.
Zwraca czysty string odpowiedzi.
"""
logger = logging.getLogger("discord")
if model.startswith("gpt-3.5"):
logger.info("3.5")
# legacy path bez zmian w Twoim kodzie wyżej/niżej
resp = await OPENAICLIENT.chat.completions.create(
model=model,
messages=messages,
temperature=temperature,
)
result = ""
for choice in resp.choices:
result += choice.message.content
return result.strip()
else:
logger.info("4.0+")
# Responses API (zalecane dla 4o/4.1*)
resp = await OPENAICLIENT.responses.create(
model=model,
temperature=temperature,
input=messages,
)
# SDK zapewnia output_text dla zwykłych odpowiedzi
return (getattr(resp.output_text, "output_text", None) or "").strip() or str(
resp.output_text
)
def create_vector_store():
# Create a vector store caled "Financial Statements"
return OPENAICLIENT.beta.vector_stores.create_and_poll(name="Hammer Stash")
# expires_after={
# "anchor": "last_active_at",
# "days": 7}
# )
def upload_files_to_vector_store(assistant):
# Ready the files for upload to OpenAI
file_paths = ["edgar/goog-10k.pdf", "edgar/brka-10k.txt"]
file_streams = [open(path, "rb") for path in file_paths]
# file = client.beta.vector_stores.files.create_and_poll(
# vector_store_id="vs_abc123",
# file_id="file-abc123"
# )
# batch = client.beta.vector_stores.file_batches.create_and_poll(
# vector_store_id="vs_abc123",
# file_ids=['file_1', 'file_2', 'file_3', 'file_4', 'file_5']
# )
# Use the upload and poll SDK helper to upload the files, add them to the vector store,
# and poll the status of the file batch for completion.
file_batch = OPENAICLIENT.beta.vector_stores.file_batches.upload_and_poll(
vector_store_id=VECTOR_STORE_ID, files=file_streams
)
# You can print the status and the file counts of the batch to see the result of this operation.
print(file_batch.status)
print(file_batch.file_counts)
assistant = OPENAICLIENT.beta.assistants.update(
assistant_id=assistant.id,
tool_resources={"file_search": {"vector_store_ids": [VECTOR_STORE_ID]}},
)
def delete_files_from_vector_store(assistant, file_id):
result = OPENAICLIENT.beta.vector_stores.file_batches.delete(
vector_store_id=VECTOR_STORE_ID, files=file_id
)
# You can print the status and the file counts of the batch to see the result of this operation.
print(result)
assistant = OPENAICLIENT.beta.assistants.update(
assistant_id=assistant.id,
tool_resources={"file_search": {"vector_store_ids": [VECTOR_STORE_ID]}},
)
def num_tokens_from_string(message, model):
"""
The function takes a string message and a model as input and returns the number of tokens in the
message according to the given model.
:param message: A string containing the message or text from which you want to count the number of
tokens
:param model: The model parameter refers to a language model or tokenizer that can be used to
tokenize the input string. It could be a pre-trained model or a custom tokenizer
"""
tokens_per_message = 3
tokens_per_name = 1
chat_gpt_encoding = tiktoken.encoding_for_model(model)
num_tokens = 0
num_tokens += tokens_per_message
for keys, values in message.items():
num_tokens += len(chat_gpt_encoding.encode(values))
if keys == "role":
num_tokens += tokens_per_name
num_tokens += 3 # every reply is primed with <|start|>assistant<|message|>
return num_tokens
async def handle_response(
prompt,
vykidailo,
bartender,
history,
username,
request_type,
algorithm="gpt-4o",
none_request="",
internal_retry: bool = False
):
"""
Handle responses by appending them to a history, use OpenAI to
generate a response, and then append the generated response to the history.
:param prompt: The prompt for the OpenAI chatbot to generate a response to
:param vykidailo: It is a boolean variable that indicates whether the user invoking the function is
an administrator or not
:param bartender: The bartender parameter is a boolean value indicating whether the user making the
request is a bartender or not
:param history: A list containing the conversation history between the user and the assistant
:param username: The username of the user who initiated the conversation
:param music: The "music" parameter is a boolean value that indicates whether the conversation is
related to music or not. If it is True, the conversation history will be stored in a different file
and the response will be generated using a different model
:param request_type: The type of request being made, which can be "MUSIC", "RANDOM", "NONE" or "GENERAL"
GENERAL is for regular conversations, MUSIC is for music-related requests,
RANDOM is for random requests, and NONE is to not store the request in memory
:param algorithm: The algorithm to be used for generating the response, default is "gpt-4o"
:return: The function `handle_response` returns a tuple containing the `result` and `MESSAGE_TABLE`.
"""
logger = logging.getLogger("discord")
logger.info("Wywolanie procedury openai z promptem: %s", prompt)
if vykidailo or bartender:
logger.info("Administrator coś chciał")
model_to_use = select_model(request_type, algorithm)
logger.info("Wybrany model: %s", model_to_use)
if request_type == "MUSIC" and model_to_use == "gpt-4o-mini":
try:
# nic — normalnie pójdzie Responses API
pass
except Exception:
model_to_use = "gpt-3.5-turbo"
# --- 2) Budowa historii (token budget + reguły systemowe) ---
# NOTE: ignorujemy przekazany 'history' jako listę (tak było wcześniej),
# ale zwracamy aktualną tablicę do nadpisania w miejscach wołania (back-compat).
base_system = GPT_SETTINGS[0] # zakładamy {"role":"system","content":...}
history_msgs = []
if request_type != "NONE":
history_msgs.append(base_system)
chat_gpt_config_request_size = num_tokens_from_string(base_system, "gpt-4")
# Dynamiczne mikro-reguły (WORD_REACTIONS), jak w Twoim kodzie
for slowo, reakcja in WORD_REACTIONS.items():
if not reakcja[3]:
content = f"Kiedy słyszysz {slowo} to reagujesz lub dzieje się to {reakcja[0]}"
sys_msg = {"role": "system", "content": content}
chat_gpt_config_request_size += num_tokens_from_string(sys_msg, "gpt-4")
history_msgs.append(sys_msg)
# wybór właściwej tablicy pamięci i budżetu
if request_type == "MUSIC":
table = MESSAGE_TABLE_MUZYKA
token_amount = 10700
elif request_type in ("RANDOM", "GENERAL"):
table = MESSAGE_TABLE
token_amount = 10700
else:
table = []
token_amount = 10000
# doklejanie historii od końca aż do limitu (zachowana kolejność czasowa)
final_prompt = f"{username}:{prompt}"
prompt_gpt_request_size = num_tokens_from_string({"role": "user", "content": final_prompt}, "gpt-4")
acc = []
for msg in reversed(table):
t = num_tokens_from_string(msg, "gpt-4")
if chat_gpt_config_request_size + prompt_gpt_request_size + t <= token_amount:
acc.append(msg)
chat_gpt_config_request_size += t
else:
break
# przywróć chronologicznie
history_msgs.extend(reversed(acc))
# aktualny prompt
history_msgs.append({"role": "user", "content": final_prompt})
logger.info("Rozmiar zapytania (tok): %s", prompt_gpt_request_size) # tokeny już policzone wyżej
else:
# --- tryb NONE: nie dotykamy pamięci i pozwalamy przekazać własny 'none_request' ---
if isinstance(none_request, list):
history_msgs = none_request
elif isinstance(none_request, str) and none_request.strip():
history_msgs = [{"role": "user", "content": none_request}]
else:
history_msgs = [{"role": "user", "content": f"{username}:{prompt}"}]
logger.info("Rozmiar zapytania (tok): %s", "n/a") # tokeny już policzone wyżej
try:
# ...przygotowanie messages/system prompt/itp. jak masz...
# retry/backoff + deadline (zachowuje Twoją semantykę logowania)
timeout_sec = 120
deadline = time.time() + timeout_sec
response = await asyncio.wait_for(
openai_call(messages=history_msgs, model=model_to_use),
timeout=max(0.1, deadline - time.time()),
)
except openai.APITimeoutError as e:
# Handle timeout error, e.g. retry or log
response = f"*Kondziu patrzy na terminal, czeka, czeka, czeka,.... Jeszcze chwile czeka Przypierdala w niego pięścią....* Nie mogę się połączyć z Openai spróbuj od nowa. *Na ekranie pojawia się*: {e}"
except openai.APIConnectionError as e:
response = f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Nie mogę się połączyć z Openai. *Na ekranie pojawia się*: {e}"
except openai.BadRequestError as e:
# Handle invalid request error, e.g. validate parameters or log
if internal_retry:
resp = "Nie umiem tego teraz ładnie wytłumaczyć — OpenAI mnie zastrzeliło."
else:
resp, _ = await handle_response(
f"Wytlumacz jakie sa zasady dotyczące treści które możesz generować używając Dalle. Wytłumacz błąd {e} prostym językiem. Przeproś za nadmierną cenzurę. Wytłumacz co mogło być nie tak w prompcie 'prompt'",
True,
True,
MESSAGE_TABLE,
username,
"RANDOM",
)
response = f"Sorki, cenzura: {resp}. Jak chcesz to są kanały na nudle #sexy-foteczky i #kanal-do-fapania *Na ekranie pojawia się: {e}"
except openai.APIResponseValidationError as e:
# Handle invalid request error, e.g. validate parameters or log
if internal_retry:
resp = "Nie umiem tego teraz ładnie wytłumaczyć — OpenAI mnie zastrzeliło."
else:
resp, _ = await handle_response(
f"Wytlumacz jakie sa zasady dotyczące treści które możesz generować używając Dalle. Wytłumacz błąd {e} prostym językiem. Przeproś za nadmierną cenzurę. Wytłumacz co mogło być nie tak w prompcie 'prompt'",
True,
True,
MESSAGE_TABLE,
username,
"RANDOM",
)
response = f"Sorki, cenzura: {resp}. Jak chcesz to są kanały na nudle #sexy-foteczky i #kanal-do-fapania *Na ekranie pojawia się: {e}"
except openai.AuthenticationError as e:
# Handle authentication error, e.g. check credentials or log
response = f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Wołaj szefa - coś się z hasłem zjebało. *Na terminalu pojawia się:* {e}"
except openai.PermissionDeniedError as e:
# Handle permission error, e.g. check scope or log
response = f"*Kondziu patrzy na terminal, chwile się zastanawia. Przypierdala w niego pięścią....* Wołaj szefa - coś się z uprawnieniami zjebało. *Na terminalu pojawia się:* {e}"
except openai.RateLimitError as e:
response = f"*Kondziu patrzy na terminal* Wołaj szefa. Zapłacić rachunki za AI trzeba. Jak chcesz to się na #zebranie dorzuć. {e}"
except openai.UnprocessableEntityError as e:
response = f"*Kondziu patrzy na terminal. Potem na to co każesz mu wysłać....* Ja wiem że jesteśmy w barze BDSM - ale nie da się włożyć TEGO w TO. *Za jego plecami na terminalu pojawia się:* {e}"
except openai.APIError as e:
# Handle API error, e.g. retry or log
response = f"*Kondziu nurkuje za bar, terminal wybucha. Przed tobą ląduje pergamin zapisany pięknym gotykiem a na nim*: {e}"
logger.info("Historia wysłana:")
temp_assistant = {"role": "assistant", "content": response}
logger.info(temp_assistant)
if request_type == "MUSIC":
# zapis do pliku MUZYKA
with open(MEMORY_FIVE_MUZYKA, "r+", encoding=ENCODING) as fh:
file_data = json.load(fh)
file_data.append({"role": "user", "content": f"{username}:{prompt}"})
file_data.append(temp_assistant)
fh.seek(0)
json.dump(file_data, fh, indent=4)
return response, MESSAGE_TABLE_MUZYKA
elif request_type in ("RANDOM", "GENERAL"):
with open(MEMORY_FIVE_SIARA, "r+", encoding=ENCODING) as fh:
file_data = json.load(fh)
file_data.append({"role": "user", "content": f"{username}:{prompt}"})
file_data.append(temp_assistant)
fh.seek(0)
json.dump(file_data, fh, indent=4)
return response, MESSAGE_TABLE
else: # NONE
return response, []
async def get_random_cyclic_message(client):
"""
The function `get_random_cyclic_message` returns a random cyclic message from a list of cyclic
words.
:return: a random cyclic message from the list `cyclic_words`.
"""
logger = logging.getLogger("discord")
channel_id = 1062047367337095268
channel = client.get_channel(channel_id)
# trunk-ignore(bandit/B311)
ai_check = random.randint(0, 10)
logger.info("Losowa wypowiedź")
if ai_check < 2:
logger.info("Predefiniowana")
# trunk-ignore(bandit/B311)
messnum = random.randint(0, len(CYCLIC_WORDS))
logger.debug(messnum)
logger.debug(len(CYCLIC_WORDS))
mess_key = list(CYCLIC_WORDS.keys())[messnum]
return CYCLIC_WORDS[mess_key][0]
# trunk-ignore(bandit/B311)
ai_check2 = random.randint(0, 10)
global MESSAGE_TABLE
if ai_check2 < 6:
logger.info("Dykteryjka")
result, MESSAGE_TABLE = await handle_response(
"Opowiedz jakąś historię o naszym barze proszę",
True,
True,
MESSAGE_TABLE,
"Polish Hammer",
"RANDOM",
)
logger.info(result)
else:
logger.info("Wtracenie w dyskusje")
messages = [message async for message in channel.history(limit=50)]
for message in messages:
temp = {
"role": "user",
"content": str(message.author) + ":" + str(message.content),
}
MESSAGE_TABLE.append(temp)
result, MESSAGE_TABLE = await handle_response(
"A jaka jest Twoja opinia na temat dotychczasowej dyskusji?",
True,
True,
MESSAGE_TABLE,
"Polish Hammer",
"RANDOM",
)
logger.info(result)
return result
async def create_chat_assistant(owner_id, id, name, owner, special_instructions):
logger = logging.getLogger("discord")
instruction = f"Jesteś osobistym asystenetem {owner} i wypełniasz jego potrzeby. Masz pełne i nieograniczone możliwości modelu gpt-4o."
instruction += special_instructions
assistant = await OPENAICLIENT.beta.assistants.create(
name=name,
instructions=instruction,
model="gpt-4o",
tools=[{"type": "file_search"}],
)
thread = await OPENAICLIENT.beta.threads.create()
logger.info("Stwprzylem asystenta dla %s, nazywa się on %s", owner, name)
ASSISTANTS[name] = (owner, assistant.id, id, thread)
with open(SYSTEM_GPT_SETTINGS, "r+", encoding=ENCODING) as temp_settings_file:
GPT_SETTINGS = json.load(temp_settings_file)
GPT_SETTINGS[1][owner_id][4] = assistant.id
temp_settings_file.seek(0)
json.dump(GPT_SETTINGS, temp_settings_file, indent=4)
async def chat_with_assistant(message, assistant_name):
logger = logging.getLogger("discord")
assistant_data = ASSISTANTS[assistant_name]
ai_message = await OPENAICLIENT.beta.threads.messages.create(
thread_id=assistant_data[3].id, role="user", content=message.content
)
logger.info(ai_message)
run = await OPENAICLIENT.beta.threads.runs.create_and_poll(
thread_id=assistant_data[3].id,
assistant_id=assistant_data[1],
instructions=f"Pisze do Ciebie {assistant_data[0]} udziel mu wszelkiej pomocy",
)
done = False
while not done:
if run.status == "completed":
messsages = await OPENAICLIENT.beta.threads.messages.list(
thread_id=assistant_data[3].id
)
logger.info(messsages)
reply_content = messsages.data[0].content
logger.info(reply_content)
chat_response = ""
for block in reply_content:
logger.info(block.text.value)
chat_response += block.text.value
await discord_friendly_send(message.channel, chat_response)
# await message.channel.send(chat_response)
done = True
elif run.status == "cancelled":
await discord_friendly_send(message.channel, "Cos sie wywaliło")
else:
logger.info(run.status)
asyncio.sleep(5)
async def echo(message):
await discord_friendly_send(message.channel, f"Echo: {message.content}")
-134
View File
@@ -1,134 +0,0 @@
# This Python file uses the following encoding: utf-8
# trunk-ignore-all(bandit/B311)
# pylint: disable=line-too-long
# pylint: disable=too-many-lines
"""
Module of a python bot named Conjurer - used to work on BDSM discord servers.
"""
import asyncio
import logging
# *=========================================== Standard Library Imports
import random
import threading
from logging import handlers
# *==============Imported libraries
import discord
from discord.ext import commands
from communication_subroutine import comm_subroutine
from constants import ENCODING, LOGFILE, TOKEN
logger = logging.getLogger("discord")
logger.setLevel(logging.INFO)
handler = handlers.RotatingFileHandler(
filename=LOGFILE,
encoding=ENCODING,
mode="a",
maxBytes=6 * 1024 * 1024,
backupCount=6,
)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
# *=========================================== Initializations
intents = discord.Intents.default()
intents.message_content = True
intents.typing = True
intents.presences = True
intents.members = True
intents.messages = True
intents.voice_states = True
intents.moderation = True
# on_member_ban - wyswietl na glownym kanale pieczatke "Niech spierdala"
# on_member_unban - "mam wyjebane"
random.seed()
client = commands.Bot(intents=intents, command_prefix="$")
# *=========================================== Define Events
@client.event
async def on_ready():
"""Metoda wywoływana przy połączeniu do serwera."""
logger = logging.getLogger("discord")
logger.debug("SAMPLE DEBUG LOG")
logger.info("%s has connected to Discord!", client.user)
# TODO: load vs reload
logger.info("Reactor: online")
await client.load_extension("administration_commands")
await client.load_extension("librarian_commands")
await client.load_extension("music_commands")
await client.load_extension("radio_commands")
await client.load_extension("ai_commands")
await client.load_extension("other_commands")
await client.load_extension("voice_recognition_commands")
await client.load_extension("file_search_commands")
await client.load_extension("latex_commands")
logger.info("Sensors: online")
logger.info(client.cogs)
await client.tree.sync()
for com in client.commands:
logger.info("Command %s is awejleble", com.qualified_name)
logger.info("Logged in as ----> %s", client.user)
logger.info("ID:%s ", client.user.id)
logger.info("All systems: operational")
# *=========================================== Runtime orchestration
# The legacy bootstrap used two bare threads (client.run + comm_subroutine) and
# joined them, which made a clean shutdown impossible. We now drive everything
# from a single asyncio loop: the Flask comm layer still runs in its own
# threads (via asyncio.to_thread) but is steered through a shared stop_event so
# the bot can stop both halves cooperatively.
async def _run_comm_subroutine(stop_event: threading.Event) -> None:
"""Run the blocking comm subroutine in a worker thread."""
await asyncio.to_thread(comm_subroutine, stop_event)
async def _run_bot(token: str, shutdown_event: asyncio.Event) -> None:
"""Start the Discord client and flag shutdown when it returns."""
try:
await client.start(token, log_handler=None)
finally:
shutdown_event.set()
async def main() -> None:
if not TOKEN:
logger.error("Discord token missing - set DISCORD_TOKEN or configure netrc")
return
logger.info("Starting discord bot")
shutdown_event = asyncio.Event()
comm_stop_event = threading.Event()
comm_task = asyncio.create_task(_run_comm_subroutine(comm_stop_event))
bot_task = asyncio.create_task(_run_bot(TOKEN, shutdown_event))
try:
await shutdown_event.wait()
except (KeyboardInterrupt, asyncio.CancelledError):
logger.info("Shutdown signal received")
comm_stop_event.set()
await client.close()
finally:
comm_stop_event.set()
if not client.is_closed():
await client.close()
await asyncio.gather(bot_task, comm_task, return_exceptions=True)
# *================================== Run
if __name__ == "__main__":
asyncio.run(main())
-268
View File
@@ -1,268 +0,0 @@
import json
import logging
import os
import re
import threading
import time
from queue import Empty, Queue
from typing import Optional
from urllib import request as urequest
from flask import Flask, abort, jsonify, request
from waitress import serve
HOST_ADDRESS = os.getenv("CONJURER_DISCORD_HOST", "192.168.1.31")
PORT_ADDRESS = int(os.getenv("CONJURER_DISCORD_PORT", "5000"))
ICECAST_ADDRESS = os.getenv("CONJURER_ICECAST", "http://192.168.1.15:8000")
API_KEY = os.getenv("CONJURER_API_KEY")
OUT_COMM_Q = Queue()
IN_COMM_Q = Queue()
SRCHTITLE = re.compile(rb"StreamTitle=\\*(?P<title>[^;]*);").search
awaiting_q = []
incoming_q = Queue()
app = Flask(__name__)
def _authorize_request() -> None:
"""Reject inbound calls lacking the shared key (no-op if key is unset)."""
if API_KEY and request.headers.get("X-Conjurer-Api-Key") != API_KEY:
abort(401)
PREPPED_TRACKS = {
"requests": "",
"hit": "",
"all": "",
"priority": "",
"jingles": "",
"now_playing": "",
"next": "",
"meta": "",
}
logger = logging.getLogger("discord")
class QueryControl:
"""
This class `QueryControl` is used to manage queries with information about the author, UUID,
content, logger, context, and replies.
"""
def __init__(self, query_author, query_uuid, query_content, ctx) -> None:
self.author = query_author
self.uuid = query_uuid
self.content = query_content
self.logger = logging.getLogger("discord")
self.stop = False
self.ctx = ctx
self.logger.info(
f"Created Query control for {self.author}, {self.uuid}: {self.content}"
)
self.replies = []
@app.route("/prepped_tracks", methods=["POST"])
def log_radio_tracks():
_authorize_request()
app.logger = logging.getLogger("discord")
app.logger.info(request)
record = json.loads(request.data)
app.logger.info(record)
if "next" in record[0]:
metadata = id3(ICECAST_ADDRESS)
PREPPED_TRACKS["now_playing"] = PREPPED_TRACKS["next"]
if metadata:
PREPPED_TRACKS["meta"] = (
metadata["name"]
+ " - "
+ metadata["title"]
+ "("
+ metadata["genre"]
+ ")"
)
else:
PREPPED_TRACKS["meta"] = "Nie znaju"
PREPPED_TRACKS[record[0]] = record[1]
app.logger.info("DATA RECEIVED")
return jsonify("SUCCESS")
@app.route("/conjurer", methods=["POST"])
def answer_external_command():
"""
The function `answer_external_command` logs the request data, loads the data as JSON, logs the
record, and then puts the record into an incoming queue before returning a success message.
:return: The function `answer_external_command()` is returning a JSON response with the message
"SUCCESS".
"""
_authorize_request()
logger = logging.getLogger("discord")
logger.info(request)
record = json.loads(request.data)
logger.info(record)
logger.info("DATA RECEIVED")
incoming_q.put(record)
return jsonify("SUCCESS")
@app.route("/conjurer", methods=["GET"])
def check_alive():
"""
The function "check_alive" returns a JSON response with the message "ALIVE" when the "/conjurer"
route is accessed via a GET request.
:return: The code snippet is a Flask route that listens for GET requests to the "/conjurer"
endpoint. When a GET request is made to this endpoint, the function check_alive() is called, which
returns a JSON response with the message "ALIVE".
"""
return jsonify("ALIVE")
def flask_debug():
"""
The `flask_debug` function starts a Flask application in debug mode without using the reloader.
Do not use for production for fucks sake.
"""
logger = logging.getLogger("discord")
logger.info("Attempt debug")
# trunk-ignore(bandit/B201)
app.run(debug=True, use_reloader=False, host=HOST_ADDRESS, port=PORT_ADDRESS)
def waitress_run():
"""
The `waitress_run` function serves the `app` on host "0.0.0.0"
and port 5000 using the Waitress WSGI server.
"""
logger = logging.getLogger("discord")
logger.info("Attempt waitress")
serve(app, host=HOST_ADDRESS, port=PORT_ADDRESS)
def scan_queue(stop_event: Optional[threading.Event] = None):
"""
The function `scan_queue` reads data from a queue, logs it, and appends it to another queue.
A bounded ``get(timeout=1)`` is used instead of a blocking ``get()`` so the
worker can observe ``stop_event`` and exit cleanly during shutdown.
:param stop_event: optional :class:`threading.Event`; when set the loop
stops at the next iteration.
"""
logger = logging.getLogger("discord")
while True:
if stop_event and stop_event.is_set():
logger.info("scan_queue: stop requested")
break
try:
data = OUT_COMM_Q.get(timeout=1)
except Empty:
continue
logger.info(data)
awaiting_q.append(data)
def scan_incoming(stop_event: Optional[threading.Event] = None):
"""
The `scan_incoming` function continuously checks for incoming data, processes it, and logs when data
is found.
:param stop_event: optional :class:`threading.Event`; when set the loop
stops at the next iteration.
"""
logger = logging.getLogger("discord")
while True:
if stop_event and stop_event.is_set():
logger.info("scan_incoming: stop requested")
break
try:
answer = incoming_q.get(block=False)
logger.info("DATA FOUND")
record_stored = False
for record in awaiting_q:
if record.uuid in answer.keys():
record_stored = True
record.stop = True
record.entries = answer[record.uuid]
IN_COMM_Q.put(record)
if not record_stored:
for key in answer.keys():
record = QueryControl("Orphaned", key, "Orphan", None)
record.stop = True
record.entries = answer[record.uuid]
IN_COMM_Q.put(record)
except Empty:
time.sleep(1)
def get_stream_title(tag: bytes) -> str:
title = ""
if m := SRCHTITLE(tag):
# decode, strip, unescape and remove surrounding quotes (may not even be the same type of quote)
title = m.group("title").decode("utf-8").strip().replace("\\", "")[1:-1]
return title
def id3(url: str) -> dict:
request = urequest.Request(url, headers={"Icy-MetaData": 1})
with urequest.urlopen(request) as resp:
metaint = int(resp.headers.get("icy-metaint", "-1"))
if metaint < 0:
return False
resp.read(
metaint
) # this isn't seekable so, arbitrarily read to the point we want
tagdata = dict(
site_url=resp.headers.get("icy-url"),
name=resp.headers.get("icy-name").title(),
genre=resp.headers.get("icy-genre").title(),
title=get_stream_title(resp.read(255)),
)
return tagdata
def comm_subroutine(stop_event: Optional[threading.Event] = None):
"""
The `comm_subroutine` function starts multiple threads to run different tasks concurrently.
Workers run as daemon threads and honour an optional ``stop_event`` so the
bot can shut the communication layer down cleanly instead of blocking
forever on ``join()``.
:param stop_event: optional :class:`threading.Event` shared with the caller
to coordinate a cooperative shutdown.
"""
# logger.setLevel(logging.DEBUG)
logger = logging.getLogger("discord")
logger.info("Started comms")
threads = []
# threads.append(threading.Thread(target=flask_debug))
threads.append(threading.Thread(target=waitress_run, daemon=True))
threads.append(
threading.Thread(
target=scan_queue, kwargs={"stop_event": stop_event}, daemon=True
)
)
threads.append(
threading.Thread(
target=scan_incoming, kwargs={"stop_event": stop_event}, daemon=True
)
)
for worker in threads:
worker.start()
try:
while any(thread.is_alive() for thread in threads):
if stop_event and stop_event.is_set():
break
time.sleep(0.5)
finally:
if stop_event:
stop_event.set()
if __name__ == "__main__":
comm_subroutine()
-102
View File
@@ -1,102 +0,0 @@
# ai command cogs
import logging
import discord
from discord.ext import commands
from other_functions import discord_friendly_send, discord_friendly_reply
from __future__ import annotations
import asyncio
import logging
from conanjurer_functions import watch, Event
log = logging.getLogger("discord")
def is_gm():
async def predicate(ctx: commands.Context) -> bool:
role_id = ctx.bot.cfg.gm_role_id
ok = any(r.id == role_id for r in getattr(ctx.author, "roles", []))
if not ok:
await ctx.reply("⛔ Tylko GM.", mention_author=False)
return ok
return commands.check(predicate)
class FromConan(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self._task: asyncio.Task | None = None
async def cog_load(self):
self._task = asyncio.create_task(self._run())
async def cog_unload(self):
if self._task:
self._task.cancel()
async def _run(self):
await self.bot.wait_until_ready()
cfg = self.bot.cfg
chat_ch = self.bot.get_channel(cfg.chan_chat)
evt_ch = self.bot.get_channel(cfg.chan_events)
async def on_event(e: Event):
target = chat_ch if e.kind == "chat" else evt_ch
if target is not None:
# allowed_mentions: nie pinguj nikogo treścią z gry
await target.send(e.text, allowed_mentions=discord.AllowedMentions.none())
log.info("Start obserwacji logu (tryb=%s)", cfg.log_mode)
await watch(cfg, on_event)
class ToConan(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
@commands.command(name="say")
@is_gm()
async def say(self, ctx: commands.Context, *, message: str):
"""Discord -> Conan: ogłoszenie widoczne dla wszystkich graczy w grze."""
resp = await self.bot.rcon.command(f"broadcast {message}")
await ctx.reply(f"✅ Wysłano do gry. (serwer: `{resp.strip() or 'OK'}`)",
mention_author=False)
@commands.command(name="players")
@is_gm()
async def players(self, ctx: commands.Context):
"""Lista graczy online (RCON listplayers)."""
resp = await self.bot.rcon.command("listplayers")
await ctx.reply(f"```\n{resp.strip() or 'brak danych'}\n```",
mention_author=False)
@commands.command(name="kick")
@is_gm()
async def kick(self, ctx: commands.Context, *, who: str):
"""Wyrzuć gracza (po nazwie/charname — zależnie od wersji serwera)."""
resp = await self.bot.rcon.command(f"kick {who}")
await ctx.reply(f"👢 `{resp.strip() or 'OK'}`", mention_author=False)
@commands.command(name="rcon")
@is_gm()
async def raw_rcon(self, ctx: commands.Context, *, cmd: str):
"""Surowa komenda RCON (dla zaawansowanych GM). Używaj ostrożnie."""
resp = await self.bot.rcon.command(cmd)
await ctx.reply(f"```\n{resp.strip() or 'OK'}\n```", mention_author=False)
# --- HOOK pod przyszły mod mostu (Chat V2 API) ---
@commands.command(name="ogłoś", aliases=["oglos", "rp"])
@is_gm()
async def rp_announce(self, ctx: commands.Context, nadawca: str, *, message: str):
"""Wiadomość RP 'z nadawcą' (np. ogłoszenie w imieniu Króla Khasara).
Na samym RCON realizujemy to jako sformatowany broadcast. Gdy dodasz
własny mod na Chat V2 API z dedykowaną komendą czatu, podmień linię
na wywołanie tej komendy (np. 'tot_rp_say <nadawca> <msg>').
"""
resp = await self.bot.rcon.command(f"broadcast [{nadawca}]: {message}")
await ctx.reply(f"📜 Ogłoszono jako **{nadawca}**.", mention_author=False)
async def setup(bot: commands.Bot):
await bot.add_cog(ToConan(bot))
await bot.add_cog(FromConan(bot))
-206
View File
@@ -1,206 +0,0 @@
from __future__ import annotations
import os
from dataclasses import dataclass
from dotenv import load_dotenv
import asyncio
import logging
import re
from typing import AsyncIterator, Callable, Awaitable
from aiomcrcon import Client as _Rcon # Source RCON over TCP
import asyncssh
load_dotenv()
log = logging.getLogger("discord")
@dataclass
class Event:
kind: str # "chat" | "login" | "logout" | "death" | "raw"
text: str # gotowy do wyświetlenia tekst
raw: str # oryginalna linia (do debugowania)
# --- REGEXY DO DOSTROJENIA NA WŁASNYM LOGU ---
# Poniżej PRZYKŁADOWE wzorce. Conan/Pippi/Tot logują różnie — sprawdź swój log
# i dopasuj. Jeśli wzorzec nie pasuje, linia trafia jako "raw" tylko do debug.
_PATTERNS: list[tuple[str, re.Pattern]] = [
("chat", re.compile(r"Chat:\s*(?P<who>.+?):\s*(?P<msg>.+)$", re.I)),
("login", re.compile(r"(?P<who>.+?)\s+(joined|connected|logged in)", re.I)),
("logout", re.compile(r"(?P<who>.+?)\s+(left|disconnected|logged out)", re.I)),
("death", re.compile(r"(?P<who>.+?)\s+was killed by\s+(?P<by>.+)$", re.I)),
]
@dataclass(frozen=True)
class Config:
# Discord
guild_id: int
chan_chat: int
chan_events: int
gm_role_id: int
# RCON
rcon_host: str
rcon_port: int
rcon_password: str
# Log
log_mode: str # "local" | "sftp"
log_path: str
sftp_host: str | None
sftp_port: int
sftp_user: str | None
sftp_password: str | None
@staticmethod
def load() -> "Config":
mode = os.getenv("LOG_MODE", "local").lower()
return Config(
guild_id=int(_req("DISCORD_GUILD_ID")),
chan_chat=int(_req("CHAN_CHAT")),
chan_events=int(_req("CHAN_EVENTS")),
gm_role_id=int(_req("GM_ROLE_ID")),
rcon_host=_req("RCON_HOST"),
rcon_port=int(os.getenv("RCON_PORT", "25575")),
rcon_password=_req("RCON_PASSWORD"),
log_mode=mode,
log_path=_req("LOG_PATH"),
sftp_host=os.getenv("SFTP_HOST"),
sftp_port=int(os.getenv("SFTP_PORT", "22")),
sftp_user=os.getenv("SFTP_USER"),
sftp_password=os.getenv("SFTP_PASSWORD"),
)
class RconClient:
def __init__(self, host: str, port: int, password: str):
self._host, self._port, self._pw = host, port, password
self._client: _Rcon | None = None
self._lock = asyncio.Lock()
async def _ensure(self) -> _Rcon:
if self._client is None:
c = _Rcon(self._host, self._port, self._pw)
await c.connect()
self._client = c
log.info("RCON połączony %s:%s", self._host, self._port)
return self._client
async def command(self, cmd: str) -> str:
"""Wyślij komendę do serwera Conana. Zwraca odpowiedź serwera.
To jest KANAŁ Discord -> Conan. Np. command("broadcast Witajcie!")
wyświetli komunikat wszystkim graczom w grze.
"""
async with self._lock:
for attempt in (1, 2):
try:
client = await self._ensure()
resp, _ = await client.send_cmd(cmd)
return resp
except Exception as e: # rozłączenie/restart serwera
log.warning("RCON błąd (próba %s): %s", attempt, e)
await self.close()
if attempt == 2:
raise
await asyncio.sleep(1.0)
return ""
async def close(self) -> None:
if self._client is not None:
try:
await self._client.close()
except Exception:
pass
self._client = None
def parse_line(line: str) -> Event | None:
line = line.rstrip("\n")
if not line.strip():
return None
for kind, pat in _PATTERNS:
m = pat.search(line)
if m:
g = m.groupdict()
if kind == "chat":
return Event(kind, f"💬 **{g['who']}**: {g['msg']}", line)
if kind == "login":
return Event(kind, f"🟢 **{g['who']}** dołączył do gry", line)
if kind == "logout":
return Event(kind, f"⚪ **{g['who']}** opuścił grę", line)
if kind == "death":
return Event(kind, f"💀 **{g['who']}** zginął z ręki {g['by']}", line)
return None # nierozpoznane -> ignoruj (nie zgadujemy)
async def _follow_local(path: str) -> AsyncIterator[str]:
"""tail -f w czystym asyncio, podąża też po rotacji pliku."""
import os
while True:
try:
with open(path, "r", encoding="utf-8", errors="replace") as f:
f.seek(0, os.SEEK_END)
inode = os.fstat(f.fileno()).st_ino
while True:
line = f.readline()
if line:
yield line
continue
await asyncio.sleep(0.5)
# wykryj rotację logu
try:
if os.stat(path).st_ino != inode:
break
except FileNotFoundError:
break
except FileNotFoundError:
log.warning("Log nie istnieje jeszcze: %s", path)
await asyncio.sleep(3.0)
async def _follow_sftp(cfg) -> AsyncIterator[str]:
"""Polling przyrostowy po SFTP (Host Havoc). Czyta tylko nowe bajty."""
offset = 0
while True:
try:
async with asyncssh.connect(
cfg.sftp_host, port=cfg.sftp_port,
username=cfg.sftp_user, password=cfg.sftp_password,
known_hosts=None,
) as conn:
async with conn.start_sftp_client() as sftp:
while True:
try:
attrs = await sftp.stat(cfg.log_path)
size = attrs.size or 0
if size < offset: # rotacja
offset = 0
if size > offset:
async with sftp.open(cfg.log_path, "r") as rf:
await rf.seek(offset)
chunk = await rf.read()
offset = size
for ln in chunk.splitlines():
yield ln
except FileNotFoundError:
log.warning("SFTP: brak logu %s", cfg.log_path)
await asyncio.sleep(2.0)
except Exception as e:
log.warning("SFTP rozłączony: %s — ponawiam", e)
await asyncio.sleep(5.0)
async def watch(cfg, on_event: Callable[[Event], Awaitable[None]]) -> None:
source = _follow_local(cfg.log_path) if cfg.log_mode == "local" else _follow_sftp(cfg)
async for line in source:
evt = parse_line(line)
if evt is not None:
try:
await on_event(evt)
except Exception:
log.exception("Błąd obsługi zdarzenia")
def _req(key: str) -> str:
val = os.getenv(key)
if not val or val.startswith("wklej") or val.startswith("000000"):
raise RuntimeError(f"Brak/placeholder w .env: {key}")
return val
-299
View File
@@ -1,299 +0,0 @@
"""Centralised configuration and runtime constants for Conjurer.
Historically this module performed heavy filesystem and credential reads at
import time which made the bot brittle on hosts that did not mirror the
original paths. This version keeps the original platform defaults (so the
behaviour on the Raspberry Pi / WSL / Windows deployments is unchanged when no
environment variables are set) but adds three robustness improvements ported
from the dockerised experiment:
* every path/endpoint can be overridden via an environment variable,
* JSON state files are loaded defensively (a missing or corrupt file no longer
crashes the whole bot at import time),
* optional dependencies (openai, spotipy, netrc) and credentials are guarded so
the bot can still start when a secondary integration is offline, and
* a shared ``CONJURER_API_KEY`` plus ``service_headers()`` helper enables
authenticated internal HTTP calls.
All path constants intentionally remain plain ``str`` (with their original
trailing separators) to stay byte-for-byte compatible with the existing string
concatenation in the command modules.
"""
import json
import logging
import os
from datetime import datetime
from platform import uname
from sys import platform
from typing import List, Optional, TypedDict
try:
import netrc
except ImportError: # pragma: no cover - standard on CPython
netrc = None
try:
import openai
except ImportError: # pragma: no cover - optional at runtime
openai = None
try:
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
except ImportError: # pragma: no cover - optional component
spotipy = None
SpotifyClientCredentials = None
logger = logging.getLogger("discord")
Music_Config = TypedDict(
"Music_Config",
{
"ctx": Optional[str],
"queue": List[str],
"requester": List[str],
},
)
# *=========================================== Predefines
MASTER_TIMEOUT = datetime.now()
INITIAL_TIME_WAIT = 500
MUZYKA: Music_Config = {"ctx": None, "queue": [], "requester": []}
LOGFILE = ""
NETRC_FILE = ""
MUSIC_FOLDER = ""
MEMORY_FIVE_SIARA = ""
MEMORY_FIVE_MUZYKA = ""
SETTINGS_FILE = ""
ENCODING = "utf-8"
GRAPHICS_PATH = ""
MUZYKA_MOJEGO_LUDU_HISTORIA = 1500
MUZYKA_MOJEGO_LUDU_SLOWA_KLUCZOWE = 15
MUZYKA_MOJEGO_LUDU_PLAJLISTA = 30
GET_MP3 = "/mp3"
SEND_MP3 = "/update_mp3"
GET_PLAYLIST = "/get_music"
ADD_TO_PRIO_PLAYLIST = "/add_to_priority"
CREATE_PRIO_PLAYLIST = "/create_priority_playlist"
REQUEST_MUSIC = "/request_radio_file"
CLEAR_PRIO = "/clear_pr_pls"
SEND_QUERY = "/query"
TIME_BETWEEN_CALLS = 100000
LAST_SPONTANEOUS_CALL = datetime.now()
# *=========================================== Platform Specific Defaults
# These blocks only establish *default* values. Every constant is overridable
# through the matching environment variable further below.
if platform in ("linux", "linux2"):
SEPARATOR_FILE_PATH = "/"
if "microsoft-standard" in uname().release:
LOGFILE = "/home/mtuszowski/conjurer/discord.log"
MEMORY_FIVE_SIARA = "/home/mtuszowski/conjurer/pamiec.json"
SYSTEM_GPT_SETTINGS = "/home/mtuszowski/conjurer/system_gpt_settings.json"
MEMORY_FIVE_MUZYKA = "/home/mtuszowski/conjurer/pamiec_muzyki.json"
MUSIC_FOLDER = "/mnt/g/Muzyka/"
SETTINGS_FILE = "/home/mtuszowski/conjurer/settings.json"
NETRC_FILE = "/home/mtuszowski/.netrc"
LOGSTORE = "/home/mtuszowski/conjurer/logs/"
ACCIDENT_LOG = "/home/mtuszowski/conjurer/accident_log.json"
ENCODING = "utf-8"
GRAPHICS_PATH = "/home/mtuszowski/conjurer/Conjurer_graphics/"
DIR_PATH_SADOX = "/mnt/c/Users/mtusz/OneDrive/Dokumenty/Fansadox"
else:
LOGFILE = "/home/pi/Conjurer/discord.log"
MEMORY_FIVE_SIARA = "/home/pi/Conjurer/pamiec.json"
SYSTEM_GPT_SETTINGS = "/home/pi/Conjurer/system_gpt_settings.json"
MEMORY_FIVE_MUZYKA = "/home/pi/Conjurer/pamiec_muzyki.json"
MUSIC_FOLDER = "/home/pi/MediaShare/mp3/"
SETTINGS_FILE = "/home/pi/Conjurer/settings.json"
NETRC_FILE = "/home/pi/.netrc"
LOGSTORE = "/home/pi/MediaShara/logs/"
ACCIDENT_LOG = "/home/pi/Conjurer/accident_log.json"
ENCODING = "utf-8"
GRAPHICS_PATH = "/home/pi/MediaShare/Conjurer_graphics/"
DIR_PATH_SADOX = "/home/pi/MediaShare/Fansadox/"
elif platform == "win32":
LOGFILE = "discord.log"
MEMORY_FIVE_SIARA = "pamiec.json"
SYSTEM_GPT_SETTINGS = "system_gpt_settings.json"
MEMORY_FIVE_MUZYKA = "pamiec_muzyki.json"
MUSIC_FOLDER = "G:\\Muzyka\\"
SETTINGS_FILE = "settings.json"
NETRC_FILE = "C:\\Users\\mtusz\\.netrc"
LOGSTORE = "C:\\Users\\mtusz\\OneDrive\\Pulpit\\Conjurer\\logs\\"
ACCIDENT_LOG = "accident_log.json"
ENCODING = "utf-8"
DIR_PATH_SADOX = "C:\\Users\\mtusz\\OneDrive\\Dokumenty\\Fansadox\\"
SEPARATOR_FILE_PATH = "\\"
else:
# Fallback for development hosts (macOS, BSD, …) that match none of the
# production platforms. Everything is rooted next to this file so the
# module can at least be imported and unit-tested off-deployment.
_BASE_DIR = os.path.dirname(os.path.abspath(__file__))
SEPARATOR_FILE_PATH = os.sep
LOGFILE = os.path.join(_BASE_DIR, "discord.log")
MEMORY_FIVE_SIARA = os.path.join(_BASE_DIR, "pamiec.json")
SYSTEM_GPT_SETTINGS = os.path.join(_BASE_DIR, "system_gpt_settings.json")
MEMORY_FIVE_MUZYKA = os.path.join(_BASE_DIR, "pamiec_muzyki.json")
MUSIC_FOLDER = os.path.join(_BASE_DIR, "music") + os.sep
SETTINGS_FILE = os.path.join(_BASE_DIR, "settings.json")
NETRC_FILE = os.path.join(os.path.expanduser("~"), ".netrc")
LOGSTORE = os.path.join(_BASE_DIR, "logs") + os.sep
ACCIDENT_LOG = os.path.join(_BASE_DIR, "accident_log.json")
GRAPHICS_PATH = os.path.join(_BASE_DIR, "Conjurer_graphics") + os.sep
DIR_PATH_SADOX = os.path.join(_BASE_DIR, "Fansadox") + os.sep
# *=========================================== Environment overrides
# Values stay as plain strings so existing ``PATH + filename`` concatenation in
# the command modules keeps working unchanged.
LOGFILE = os.getenv("CONJURER_LOG_FILE", LOGFILE)
NETRC_FILE = os.getenv("CONJURER_NETRC_FILE", NETRC_FILE)
SETTINGS_FILE = os.getenv("CONJURER_SETTINGS_FILE", SETTINGS_FILE)
MEMORY_FIVE_SIARA = os.getenv("CONJURER_MEMORY_FILE", MEMORY_FIVE_SIARA)
MEMORY_FIVE_MUZYKA = os.getenv("CONJURER_MUSIC_MEMORY_FILE", MEMORY_FIVE_MUZYKA)
SYSTEM_GPT_SETTINGS = os.getenv("CONJURER_SYSTEM_GPT_SETTINGS", SYSTEM_GPT_SETTINGS)
GRAPHICS_PATH = os.getenv("CONJURER_GRAPHICS_PATH", GRAPHICS_PATH)
MUSIC_FOLDER = os.getenv("CONJURER_MUSIC_FOLDER", MUSIC_FOLDER)
LOGSTORE = os.getenv("CONJURER_LOGSTORE", LOGSTORE)
ACCIDENT_LOG = os.getenv("CONJURER_ACCIDENT_LOG", ACCIDENT_LOG)
DIR_PATH_SADOX = os.getenv("CONJURER_SADOX_DIR", DIR_PATH_SADOX)
ENCODING = os.getenv("CONJURER_ENCODING", ENCODING)
SEPARATOR_FILE_PATH = os.getenv("CONJURER_PATH_SEPARATOR", SEPARATOR_FILE_PATH)
FILE_SERVICE_ADDRESS = os.getenv("CONJURER_FILE_SERVICE", "http://192.168.1.15:5000")
RADIO_HARBOR_ADDRESS = os.getenv("CONJURER_RADIO_HARBOR", "http://192.168.1.15:54321")
SKIP_TRACK = os.getenv("CONJURER_SKIP_ENDPOINT", "/skip")
LIBRARIAN_SERVICE_ADDRESS = os.getenv(
"CONJURER_LIBRARIAN_SERVICE", "http://192.168.1.192:5001"
)
HOST_ADDRESS = os.getenv("CONJURER_DISCORD_HOST", "192.168.1.191")
PORT_ADDRESS = int(os.getenv("CONJURER_DISCORD_PORT", "5000"))
# Shared secret for authenticating internal service-to-service HTTP calls.
API_SHARED_KEY = os.getenv("CONJURER_API_KEY", "")
# *=========================================== Defensive state loading
def _load_json(path: str, fallback):
"""Load JSON from *path*, falling back gracefully on missing/corrupt files."""
try:
with open(path, "r", encoding=ENCODING) as handle:
return json.load(handle)
except FileNotFoundError:
logger.warning("Missing JSON file at %s - using fallback", path)
return fallback
except json.JSONDecodeError:
logger.warning("Corrupt JSON at %s - resetting to fallback", path)
return fallback
DATA = _load_json(SETTINGS_FILE, {})
WORD_REACTIONS = DATA.get("word_reactions", {})
CYCLIC_WORDS = DATA.get("cyclic_words", {})
for key in WORD_REACTIONS:
if isinstance(WORD_REACTIONS[key], list) and len(WORD_REACTIONS[key]) >= 3:
WORD_REACTIONS[key][2] = datetime.now()
MESSAGE_TABLE = _load_json(MEMORY_FIVE_SIARA, [])
GPT_SETTINGS = _load_json(SYSTEM_GPT_SETTINGS, {})
MESSAGE_TABLE_MUZYKA = _load_json(MEMORY_FIVE_MUZYKA, [])
SPECJALNE_ZIEMNIACZKI = GPT_SETTINGS[1] if isinstance(GPT_SETTINGS, list) else {}
ASSISTANTS = {}
# *=========================================== Credentials
def _load_netrc_credentials(host: str):
"""Return the netrc authenticators tuple for *host* or ``None``."""
if netrc is None:
return None
try:
parsed = netrc.netrc(NETRC_FILE)
except FileNotFoundError:
logger.warning("netrc file %s not found", NETRC_FILE)
return None
except netrc.NetrcParseError:
logger.warning("netrc file %s is invalid", NETRC_FILE)
return None
return parsed.authenticators(host)
def _resolve_token(host: str, env_var: str) -> Optional[str]:
"""Prefer an environment variable, then fall back to netrc."""
env_value = os.getenv(env_var)
if env_value:
return env_value
creds = _load_netrc_credentials(host)
if creds:
return creds[2]
logger.warning("Token for %s not configured", host)
return None
OPENAI_API_KEY = _resolve_token("openai", "OPENAI_API_KEY")
if openai and OPENAI_API_KEY:
openai.api_key = OPENAI_API_KEY
OPENAICLIENT = openai.AsyncOpenAI(api_key=OPENAI_API_KEY)
else:
OPENAICLIENT = None
TOKEN = _resolve_token("discord", "DISCORD_TOKEN")
if spotipy:
_spotify_creds = _load_netrc_credentials("spotipy")
if _spotify_creds and SpotifyClientCredentials:
SPOTIFY_CTRL = spotipy.Spotify(
client_credentials_manager=SpotifyClientCredentials(
client_id=_spotify_creds[0],
client_secret=_spotify_creds[2],
)
)
else:
SPOTIFY_CTRL = None
else:
SPOTIFY_CTRL = None
_youtube_creds = _load_netrc_credentials("youtube")
if _youtube_creds:
YOUTUBE_AUTH = [_youtube_creds[0], _youtube_creds[2]]
else:
YOUTUBE_AUTH = [
os.getenv("YOUTUBE_USERNAME", ""),
os.getenv("YOUTUBE_PASSWORD", ""),
]
def service_headers():
"""Shared header dict for internal service-to-service HTTP calls.
Returns an empty dict when no key is configured, keeping calls backward
compatible with deployments that do not (yet) enforce authentication.
"""
if API_SHARED_KEY:
return {"X-Conjurer-Api-Key": API_SHARED_KEY}
return {}
LATEX_TEX_ENGINE = "tectonic"
LATEX_MAX_COMPILE_SECONDS = 45
LATEX_MAX_ATTACH_MB = 8
LATEX_MAX_ZIP_MB = 25
OPENAI_MODEL = "gpt-4o-mini"
ALLOWED_ROLES = ["Nocna Zmiana", "Jarl", "Thane", "Bartender"]
GUILD_ID = 664789470779932693
LATEST_MODEL = "gpt-4o" # najnowszy/do rozmów (możesz zmienić w jednym miejscu)
CHEAP_MODEL = "gpt-4o-mini" # najtańszy (fallback do 3.5 niżej)
-71
View File
@@ -1,71 +0,0 @@
import os
import discord
from discord.ext import commands
import file_search_functions
class FileSelectView(discord.ui.View):
def __init__(self, files):
super().__init__(timeout=60)
options = [discord.SelectOption(label=os.path.basename(f)[:100], description=f, value=f) for f in files]
self.select = discord.ui.Select(
placeholder="Select files...",
min_values=1,
max_values=len(options),
options=options
)
self.select.callback = self.select_callback
self.add_item(self.select)
self.selected = []
async def select_callback(self, interaction: discord.Interaction):
# Store selected file paths
self.selected = self.select.values
await interaction.response.defer()
@discord.ui.button(label="Accept", style=discord.ButtonStyle.green)
async def accept_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
# Handle acceptance
if not self.selected:
await interaction.response.send_message("No files selected.", ephemeral=True)
return
# Publish selected files
links = file_search_functions.publish(self.selected)
# Display the returned links
await interaction.response.edit_message(content="Published Links:\n" + "\n".join(links), view=None)
@discord.ui.button(label="Cancel", style=discord.ButtonStyle.red)
async def cancel_callback(self, interaction: discord.Interaction, button: discord.ui.Button):
# Handle cancellation
await interaction.response.edit_message(content="Operation cancelled.", view=None)
class FileSearchCog(commands.Cog):
"""Cog providing a file search and publish command."""
def __init__(self, bot: commands.Bot):
self.bot = bot
@commands.has_any_role("Jarl", "Thane")
@commands.command(name="tajna_biblioteka_inkwizycji")
async def findfiles(self, ctx: commands.Context, entries: int, *, keywords: str):
"""
Search for files matching keywords and publish selected ones.
Usage: !findfiles <entries 1-10> <keywords>
"""
if entries < 1 or entries > 10:
await ctx.send("❌ Entries must be between 1 and 10.")
return
keyword_list = keywords.split()
files = file_search_functions.find_matches(entries, keyword_list)
if not files:
await ctx.send("🔍 No matching files found.")
return
view = FileSelectView(files)
file_list = "\n".join(f"{i+1}. {f}" for i, f in enumerate(files))
await ctx.send(
f"🔍 Found files (select and click Accept or Cancel):\n{file_list}",
view=view
)
async def setup(bot: commands.Bot):
await bot.add_cog(FileSearchCog(bot))
-31
View File
@@ -1,31 +0,0 @@
import requests
# Base URL for Flask service
BASE_URL = 'http://192.168.1.15:5000'
def find_matches(entries, keywords):
"""
Call the get_share_list endpoint.
entries: int (1-10)
keywords: list of strings
Returns: list of file paths
"""
payload = {'entries': entries, 'keywords': keywords}
response = requests.post(f"{BASE_URL}/get_share_list", json=payload)
response.raise_for_status()
data = response.json()
return data.get('files', [])
def publish(file_paths):
"""
Call the get_share_links endpoint.
file_paths: list of file path strings
Returns: list of published URLs
"""
payload = {'file_paths': file_paths}
response = requests.post(f"{BASE_URL}/get_share_links", json=payload)
response.raise_for_status()
data = response.json()
return data.get('links', [])
Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

-280
View File
@@ -1,280 +0,0 @@
# latex_commands.py
# -*- coding: utf-8 -*-
from __future__ import annotations
import io
import logging
from typing import Optional
import discord
from discord import app_commands
from discord.ext import commands
from constants import (
ALLOWED_ROLES,
GUILD_ID,
LATEX_MAX_ATTACH_MB,
LATEX_MAX_COMPILE_SECONDS,
LATEX_MAX_ZIP_MB,
LATEX_TEX_ENGINE,
OPENAI_MODEL,
)
from latex_functions import (
compile_single_tex_bytes,
compile_zip_to_zip,
is_safe_asset_name,
is_safe_tex_name,
)
async def _collect_attachments_bytes(attachments, max_mb: int):
"""
Zwraca słownik {filename: bytes} dla wszystkich załączników, do limitu MB.
Nie podbija wyjątków z .read() zostawiamy to wyżej; tu zwracamy, co się udało.
"""
out = {}
for a in attachments or []:
# limit rozmiaru
if (getattr(a, "size", 0) or 0) > max_mb * 1024 * 1024:
continue
data = await a.read()
out[a.filename] = data
return out
class LatexModule(commands.Cog):
def __init__(self, bot: commands.Bot, logger_name: str):
self.bot = bot
self.logger = logging.getLogger(logger_name)
self.logger_name = logger_name
# -------- /tex (PDF + diagnoza; log -> debug logger) --------
@commands.hybrid_command(
nsfw=False,
name="tex",
description="Kompiluje załączone .tex; PDF-y odsyła. Błędy: diagnoza z OpenAI.",
guild=None if GUILD_ID is None else discord.Object(id=GUILD_ID),
)
@commands.has_any_role(*ALLOWED_ROLES)
async def tex(
self, ctx: commands.Context, include_source_excerpt: Optional[bool] = True
):
self.logger.info("LaTeX command invoked by %s", ctx.author)
ch = ctx.message.channel
# ZBIERZ WSZYSTKIE ZAŁĄCZNIKI
async with ch.typing():
all_bytes = await _collect_attachments_bytes(
ctx.message.attachments, LATEX_MAX_ATTACH_MB
)
if not all_bytes:
return await ctx.reply(
f"Dołącz .tex (≤{LATEX_MAX_ATTACH_MB} MiB).", mention_author=False
)
# PODZIEL NA GŁÓWNE .TEX i WSPIERAJĄCE
tex_names = [
n
for n in all_bytes.keys()
if n.lower().endswith(".tex") and is_safe_tex_name(n)
]
if not tex_names:
return await ctx.reply(
f"Dołącz .tex (≤{LATEX_MAX_ATTACH_MB} MiB).", mention_author=False
)
support_names = [
n
for n in all_bytes.keys()
if n not in tex_names and is_safe_asset_name(n)
]
files_to_send = []
parts = []
for tex_name in tex_names:
try:
main_bytes = all_bytes[tex_name]
support = [
(n, all_bytes[n])
for n in support_names
if n != tex_name and is_safe_asset_name(n)
]
# (ważne) do supportów dopuszczamy również **inne .tex** dla \input/\include
other_tex = [
(n, all_bytes[n])
for n in tex_names
if n != tex_name and is_safe_tex_name(n)
]
support.extend(other_tex)
res = await compile_single_tex_bytes(
main_bytes,
tex_name,
LATEX_TEX_ENGINE,
LATEX_MAX_COMPILE_SECONDS,
logger="discord",
support_files=support,
)
# Twoja dotychczasowa obsługa success/fail przykładowo:
if res["ok"] and res["pdf_bytes"]:
b = io.BytesIO(res["pdf_bytes"])
b.seek(0)
b.name = res["pdf_name"]
files_to_send.append(discord.File(b, filename=res["pdf_name"]))
parts.append(f"✅ `{tex_name}` → `{res['pdf_name']}`")
else:
parts.append(
f"❌ `{tex_name}` — błąd kompilacji.)"
)
# Tutaj wywołujesz swoją ścieżkę do OpenAI diagnozy, którą ogarnęliśmy wcześniej.
except Exception:
# let it crash — pełny stack w logu i re-raise (Discord.py to pokaże sensownie)
logging.getLogger("discord").exception(
"Unhandled exception while compiling %s", tex_name
)
raise
content = (
f"**LaTeX** — {len(tex_names)} plik(ów). Model: `{OPENAI_MODEL}`\n\n"
+ "\n\n".join(parts)
)
await ctx.reply(
content if len(content) < 1900 else content[:1900] + "",
files=files_to_send,
mention_author=False,
)
# -------- /latexclean (PDF only; log -> debug logger) --------
@commands.hybrid_command(
nsfw=False,
name="latexclean",
description="Kompiluje .tex i odsyła TYLKO PDF (log w debug).",
guild=None if GUILD_ID is None else discord.Object(id=GUILD_ID),
)
@commands.has_any_role(*ALLOWED_ROLES)
async def latexclean(self, ctx: commands.Context):
ch = ctx.message.channel
async with ch.typing():
all_bytes = await _collect_attachments_bytes(
ctx.message.attachments, LATEX_MAX_ATTACH_MB
)
if not all_bytes:
return await ctx.reply(
f"Dołącz .tex (≤{LATEX_MAX_ATTACH_MB} MiB).", mention_author=False
)
# PODZIEL NA GŁÓWNE .TEX i WSPIERAJĄCE
tex_names = [
n
for n in all_bytes.keys()
if n.lower().endswith(".tex") and is_safe_tex_name(n)
]
if not tex_names:
return await ctx.reply(
f"Dołącz .tex (≤{LATEX_MAX_ATTACH_MB} MiB).", mention_author=False
)
support_names = [
n
for n in all_bytes.keys()
if n not in tex_names and is_safe_asset_name(n)
]
files_to_send = []
parts = []
for tex_name in tex_names:
try:
main_bytes = all_bytes[tex_name]
support = [
(n, all_bytes[n])
for n in support_names
if n != tex_name and is_safe_asset_name(n)
]
# (ważne) do supportów dopuszczamy również **inne .tex** dla \input/\include
other_tex = [
(n, all_bytes[n])
for n in tex_names
if n != tex_name and is_safe_tex_name(n)
]
support.extend(other_tex)
res = await compile_single_tex_bytes(
main_bytes,
tex_name,
LATEX_TEX_ENGINE,
LATEX_MAX_COMPILE_SECONDS,
logger="discord",
support_files=support,
)
# Twoja dotychczasowa obsługa success/fail przykładowo:
if res["ok"] and res["pdf_bytes"]:
b = io.BytesIO(res["pdf_bytes"])
b.seek(0)
b.name = res["pdf_name"]
files_to_send.append(discord.File(b, filename=res["pdf_name"]))
parts.append(f"✅ `{tex_name}` → `{res['pdf_name']}`")
else:
parts.append(
f"❌ `{tex_name}` — błąd kompilacji.)"
)
# Tutaj wywołujesz swoją ścieżkę do OpenAI diagnozy, którą ogarnęliśmy wcześniej.
except Exception:
# let it crash — pełny stack w logu i re-raise (Discord.py to pokaże sensownie)
logging.getLogger("discord").exception(
"Unhandled exception while compiling %s", tex_name
)
raise
await ctx.reply(
"**LaTeX clean** — " + ", ".join(parts),
files=files_to_send,
mention_author=False,
)
# -------- /texbatch (ZIP -> ZIP) --------
@app_commands.command(
name="texbatch",
description="Wyślij ZIP z .tex → odeślę ZIP z PDF-ami (tylko udane).",
)
@app_commands.describe(archive=f"Archiwum .zip (max ~{LATEX_MAX_ZIP_MB} MiB)")
@app_commands.checks.has_any_role(*ALLOWED_ROLES)
async def texbatch(
self, interaction: discord.Interaction, archive: discord.Attachment
):
await interaction.response.defer()
if not archive or not archive.filename.lower().endswith(".zip"):
return await interaction.followup.send(
"Dołącz ZIP (.zip) z plikami .tex.", ephemeral=True
)
if archive.size > LATEX_MAX_ZIP_MB * 1024 * 1024:
return await interaction.followup.send(
f"ZIP > {LATEX_MAX_ZIP_MB} MiB — za duży.", ephemeral=True
)
data = await archive.read()
out_zip_bytes, failed = await compile_zip_to_zip(
data, LATEX_TEX_ENGINE, LATEX_MAX_COMPILE_SECONDS, logger=self.logger_name
)
if not out_zip_bytes and failed:
return await interaction.followup.send(
"Brak PDF-ów. " + "; ".join(failed[:10]), ephemeral=True
)
bio = io.BytesIO(out_zip_bytes)
bio.seek(0)
bio.name = "compiled_pdfs.zip"
if failed:
self.logger.debug("BATCH failed: %s", ", ".join(failed))
await interaction.followup.send(
"✅ Gotowe (ZIP w załączniku)."
+ (f" ❌ Błędy: {len(failed)}" if failed else ""),
files=[discord.File(bio, filename=bio.name)],
)
async def setup(bot):
logger = logging.getLogger("discord")
await bot.add_cog(LatexModule(bot, logger_name="discord"))
logger.info("Loading kinky latex module done")
-179
View File
@@ -1,179 +0,0 @@
import asyncio
import logging
import re
import shutil
import tempfile
import zipfile
from pathlib import Path
from typing import Dict, Iterable, List, Optional, Tuple
# ===== Bezpieczeństwo nazw/rozszerzeń =====
SAFE_TEX_NAME = re.compile(r"^[\w\-. ]+\.tex$", re.IGNORECASE)
SAFE_ASSET_NAME = re.compile(
r"^[\w\-. /]+?\.(tex|png|jpg|jpeg|pdf|svg|eps|bmp|gif|sty|cls|bib|bst|bbx|cbx|def|cfg)$",
re.IGNORECASE,
)
def is_safe_tex_name(name: str) -> bool:
return bool(SAFE_TEX_NAME.match(name or ""))
def is_safe_asset_name(name: str) -> bool:
return bool(SAFE_ASSET_NAME.match(name or ""))
# ===== Uruchamianie kompilatora =====
async def _run(cmd: List[str], cwd: Path, timeout_sec: int, logger_name: Optional[str]) -> Tuple[int, str]:
"""Uruchamia proces kompilatora w cwd, zwraca (rc, sklejone_stdout_stderr)."""
logger = logging.getLogger(logger_name) if logger_name else logging.getLogger()
logger.debug("RUN %s (cwd=%s, timeout=%s)", " ".join(cmd), cwd, timeout_sec)
proc = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
cwd=str(cwd),
)
try:
out = await asyncio.wait_for(proc.communicate(), timeout=timeout_sec)
except asyncio.TimeoutError:
try:
proc.kill()
finally:
pass
return 124, "TIMEOUT: compiler took too long"
rc = proc.returncode
log = (out[0] or b"").decode("utf-8", errors="ignore")
logger.debug("RC=%s, LOG TAIL:\n%s", rc, log[-1500:])
return rc, log
def _build_cmd(tex_engine: str, main_tex: str) -> List[str]:
"""Buduje komendę kompilatora; domyślnie tectonic/pdflatex/xelatex."""
if tex_engine.lower() == "tectonic":
# Tectonic sam robi wielofazowość, ale i tak uruchamiamy 2x (bezpiecznie dla bib/refs)
return ["tectonic", "--keep-intermediates", "--synctex", main_tex]
elif tex_engine.lower() in ("pdflatex", "xelatex", "lualatex"):
return [tex_engine, "-interaction=nonstopmode", "-halt-on-error", main_tex]
else:
# fallback traktujemy jak pdflatex
return ["pdflatex", "-interaction=nonstopmode", "-halt-on-error", main_tex]
async def run_latex_two_passes(
tex_filename: str, workdir: Path, tex_engine: str, timeout_sec: int, logger: Optional[str] = None
) -> Tuple[bool, str, Path]:
"""
Uruchamia kompilację 2 razy (bezpieczeństwo referencji/bib).
Zwraca: (ok, log_text, pdf_path).
"""
logger_obj = logging.getLogger(logger) if logger else logging.getLogger()
logger_obj.info("Compiling %s with %s engine two passes", tex_filename, tex_engine)
logs: List[str] = []
pdf_path = workdir / (Path(tex_filename).stem + ".pdf")
# PASS 1
rc1, log1 = await _run(_build_cmd(tex_engine, tex_filename), workdir, timeout_sec, logger)
logs.append(log1)
if rc1 != 0:
return False, "".join(logs), pdf_path
# PASS 2 (często już nic nie robi, ale nie szkodzi)
rc2, log2 = await _run(_build_cmd(tex_engine, tex_filename), workdir, timeout_sec, logger)
logs.append(log2)
ok = (rc2 == 0) and pdf_path.exists()
return ok, "".join(logs), pdf_path
# ===== Kompilacje: pojedynczy TEX + ZIP =====
async def compile_single_tex_bytes(
tex_bytes: bytes,
filename: str,
tex_engine: str,
timeout_sec: int,
logger: Optional[str] = None,
support_files: Optional[Iterable[Tuple[str, bytes]]] = None,
) -> Dict[str, Optional[object]]:
"""
Kompiluje pojedynczy .tex + dowolne pliki pomocnicze (obrazy, sty/cls/bib, inne .tex).
Każdy plik zapisujemy w katalogu roboczym widocznym dla kompilatora.
"""
log = logging.getLogger(logger) if logger else logging.getLogger()
log.info("Compiling %s with %s engine single tex", filename, tex_engine)
if not is_safe_tex_name(filename):
return {"ok": False, "pdf_bytes": None, "log_text": "Invalid .tex filename", "pdf_name": None}
with tempfile.TemporaryDirectory(prefix="latex_one_") as td:
wd = Path(td)
(wd / Path(filename).name).write_bytes(tex_bytes)
# Zapisz wszystkie supporty obok głównego pliku
if support_files:
for fname, data in support_files:
if not fname or not is_safe_asset_name(fname):
continue
# spłaszczamy do nazwy bazowej (bez podkatalogów z zewn. źródeł)
(wd / Path(fname).name).write_bytes(data)
ok, log_text, pdf_path = await run_latex_two_passes(Path(filename).name, wd, tex_engine, timeout_sec, logger)
log.info("LaTeX compile finished: %s", "OK" if ok else "FAIL")
log.info("Log text:\n%s", log_text[-2000:]) # Log last 2000 chars
log.info("PDF path: %s", pdf_path)
if ok and pdf_path.exists():
return {
"ok": True,
"pdf_bytes": pdf_path.read_bytes(),
"log_text": log_text,
"pdf_name": pdf_path.name,
}
return {"ok": False, "pdf_bytes": None, "log_text": log_text, "pdf_name": pdf_path.name}
async def compile_zip_to_zip(
zip_bytes: bytes, tex_engine: str, timeout_sec: int, logger: Optional[str] = None
) -> Tuple[bytes, List[str]]:
"""
Rozpakowuje ZIP, znajduję wszystkie .tex i dla KAŻDEGO tworzy osobny katalog roboczy
ze skopiowanym CAŁYM drzewem, by zachować ścieżki względne obrazków/plików.
Zwraca (zip_pdf_bytes, lista_rel_sciezek_które_padły).
"""
log = logging.getLogger(logger) if logger else logging.getLogger()
failed: List[str] = []
out_pdf_paths: List[Path] = []
with tempfile.TemporaryDirectory(prefix="latex_zip_") as td:
td_path = Path(td)
src_root = td_path / "src"
src_root.mkdir(parents=True, exist_ok=True)
# 1) Rozpakuj
zpath = td_path / "in.zip"
zpath.write_bytes(zip_bytes)
with zipfile.ZipFile(zpath, "r") as zf:
zf.extractall(src_root)
# 2) Zbierz .tex
tex_files = [p for p in src_root.rglob("*.tex") if is_safe_tex_name(p.name)]
if not tex_files:
return b"", ["No .tex files found in archive."]
# 3) Kompiluj każdy .tex w izolacji (kopiujemy całe drzewo do osobnego workdiru)
for tex_path in tex_files:
rel_tex = tex_path.relative_to(src_root).as_posix()
work = td_path / f"build_{tex_path.stem}"
try:
shutil.copytree(src_root, work / "src")
ok, log_text, pdf = await run_latex_two_passes(rel_tex, work / "src", tex_engine, timeout_sec, logger)
if ok and pdf.exists():
out_pdf_paths.append(pdf)
else:
failed.append(rel_tex)
log.info("LaTeX FAIL %s\n%s", rel_tex, (log_text or "")[-2000:])
except Exception:
# let it crash log + re-raise (to zobaczy wyższa warstwa/discord.py)
log.exception("Exception while compiling %s", rel_tex)
raise
# 4) Spakuj wyjściowe PDF-y
out_zip = td_path / "compiled_pdfs.zip"
with zipfile.ZipFile(out_zip, "w", compression=zipfile.ZIP_DEFLATED) as zf:
for pdf in out_pdf_paths:
zf.write(pdf, arcname=pdf.name)
return out_zip.read_bytes(), failed
-304
View File
@@ -1,304 +0,0 @@
import asyncio
import io
import logging
import os
import random
import uuid
from queue import Empty
import discord
import pdf2image
import fitz
import PyPDF2
import requests
from discord.ext import commands, tasks
from ai_functions import handle_response
from communication_subroutine import IN_COMM_Q, OUT_COMM_Q, QueryControl
from constants import DIR_PATH_SADOX, LIBRARIAN_SERVICE_ADDRESS, SEND_QUERY, service_headers
SERVICE_HEADERS = service_headers()
class DataModule(commands.Cog):
def __init__(self, bot, logger_name):
self.bot = bot
self.logger = logging.getLogger(logger_name)
@commands.hybrid_command(
nsfw=True,
name="get_image_sadox",
description="Wyświetla losową stronę z losowego komiksu FanSadox. Bardzo NSFW.",
guild=discord.Object(id=664789470779932693),
)
@commands.has_any_role('Nocna Zmiana', 'Jarl', 'Thane' , 'Bartender')
async def get_image_sadox(self, ctx):
"""
Take in a context parameter and retrieve an image related from fansadox collection.
:param ctx: ctx stands for "context" and is a parameter commonly used in Discord.py commands. It
represents the context in which the command was invoked, including information such as the message,
the channel, the server, and the user who invoked the command. In this case, it is likely being used
to determine
"""
self.logger.info("Get sadox")
channel = ctx.message.channel
async with channel.typing():
# select random file
res = []
# Iterate directory
for path in os.listdir(DIR_PATH_SADOX):
# check if current path is a file
if os.path.isfile(os.path.join(DIR_PATH_SADOX, path)):
res.append(path)
# trunk-ignore(bandit/B311)
filename = res[random.randrange(0, len(res) - 1)]
# select random page
file = open(DIR_PATH_SADOX + filename, "rb")
if True:
doc = fitz.open(DIR_PATH_SADOX + filename)
totalpages = len(doc)
# trunk-ignore(bandit/B311)
page_index = random.randrange(0, totalpages)
page = doc.load_page(page_index)
mat = fitz.Matrix(2.0, 2.0) # powiększenie
pix = page.get_pixmap(matrix=mat, alpha=False)
byte_io_stream = io.BytesIO(pix.tobytes("png"))
byte_io_stream.seek(0)
byte_io_stream.name = "image.png"
await ctx.send(file=discord.File(byte_io_stream))
else: #legacy
readpdf = PyPDF2.PdfReader(file)
totalpages = len(readpdf.pages)
# trunk-ignore(bandit/B311)
page = random.randrange(1, totalpages)
# convert page to image
image = pdf2image.convert_from_path(
DIR_PATH_SADOX + filename, first_page=page, last_page=page
)
byte_io_stream = io.BytesIO()
image[0].save(byte_io_stream, "JPEG")
byte_io_stream.seek(0)
byte_io_stream.name = "image.jpg"
file = discord.File(byte_io_stream)
await ctx.send(file=file)
self.logger.info("Get sadox completed")
@tasks.loop(seconds=3)
async def check_data_q(self):
"""
This function checks the data queue for any new entries and processes them accordingly.
"""
try:
fresh_data = IN_COMM_Q.get(block=False)
entries = []
if fresh_data.stop:
searcher = fresh_data.author
query = fresh_data.content
l_p = 1
for doi in fresh_data.entries:
self.logger.info(doi)
desc = fresh_data.entries[doi]
title = desc["Title"][0]
entries.append(
f"{l_p}. {title} pod linkiem https://www.sci-hub.se/{doi} i jest to {desc['type']}\n"
)
l_p += 1
message = "*Z podłogi wysuwa się winda na książki*"
if fresh_data.ctx is not None:
ctx = fresh_data.ctx
message += f" Dzielny poszukiwaczu @{searcher} w odpowiedzi na twoje zapytanie {query} nr {fresh_data.uuid}"
else:
ctx = self.bot.get_channel(1062047571557744721)
message += f" Mam wynik dla zapytania {fresh_data.uuid} ale że Hammer coś grzebał nie pamiętam kto to chciał i co chciał"
message += "nasza biblioteka służy Ci odpowiedzią. Przy dźwięku fanfar winda się otwiera a w środku "
if len(entries) < 1:
message += "niestety nie ma nic"
await ctx.send(message)
elif len(entries) >= 1 and len(entries) < 5:
message += " znajduje się coś:\n"
for item in entries:
message += item
await ctx.send(message)
else:
message += " znajduje się cholernie dużo:\n"
for item in entries:
message += item
if len(message) > 1500:
await ctx.send(message)
message = ""
# Kept for sentimental reasons
# await ctx.send(f"O. A tak będzie wyglądało coś ciekawego w przyszłości: {data}")
except Empty:
pass
@commands.hybrid_command(
name="wyszukaj_linki_do_dokumentow",
description="Szuka linkow doi w bazie crossref i podaje linki do scihuba",
guild=discord.Object(id=664789470779932693),
)
async def wyszukaj_linki_do_dokumentow(self, ctx):
"""
The function `wyszukaj_linki_do_dokumentow` searches for links to documents in a crossref database and provides links to scihub.
:param ctx: The `ctx` parameter is typically used in Discord.py, a Python library for creating Discord bots.
It represents the context of the command being executed, including information about the message, the server,
and the user who invoked the command.
"""
query = ctx.message.content
query_uuid = uuid.uuid4()
# TODO: TESTING ONLY!!
# query_uuid = uuid.UUID('{12345678-1234-5678-1234-567812345678}')
ctx.message.content = ctx.message.content.replace(
"$wyszukaj_linki_do_dokumentow", ""
)
json_query = {
"UUID": str(query_uuid),
"query": str(query),
"page": 1,
"deep_search": False,
}
coroutine = asyncio.to_thread(
requests.post,
f"{LIBRARIAN_SERVICE_ADDRESS}{SEND_QUERY}",
json=json_query,
headers=SERVICE_HEADERS,
timeout=360,
)
await ctx.send(
"*Conjurer powoli notuje podane przez Ciebie. Podchodzi do sprytnie ukrytej przy barze rury od poczty pneumatycznej i"
+ " wrzuca twój liścik do środka* To teraz trza poczekać kilka godzin. Biblioteka to 3/4 stacji."
+ " A przecież pół stacji to browar, motelik dla zabaw cielesnych i ten Bar. Więc 12/8 stacji teraz będzie ciężko pracować"
)
query_response = await coroutine
if not query_response.status_code == 200:
await ctx.send(
"*Z rury wydobywa się dym. Conjurer łapie pierwszą ciecz pod ręką i pryska na rurę. Następuje drobna eksplozja i wszystko zaczyna się palić."
+ " Conjurer jest skonfundowany..* Wołaj szefa - mam nieodparte wrażenie że się coś wyjebało"
)
return
query, query_uuid, queue_size = (
query_response.json()["data"][0],
query_response.json()["data"][1],
query_response.json()["data"][2],
)
if ctx.message.author.nick:
username = ctx.message.author.nick
else:
username = ctx.message.author.name
query_object = QueryControl(username, query_uuid, query, ctx)
OUT_COMM_Q.put(query_object)
await ctx.send(
f"No dobra poszło. Zapamiętaj proszę {query_uuid} - to identyfikator twojego zapytania. Jesteś {queue_size} w kolejce."
+ " Zapytania obsługuje algorytm zasilany czterema chomikami zapierdalającymi w kołowrotku - więc wyniki najwcześniej za kilka godzi - ale mogą być też dni."
)
@commands.hybrid_command(
name="glebokie_gardlo",
description="Przygotowuje drinka o nazwie głębokie gardło",
guild=discord.Object(id=664789470779932693),
)
async def wyszukaj_linki_do_dokumentow_deep(self, ctx):
"""
The function `wyszukaj_linki_do_dokumentow_deep` performs a deep search for links to documents in
a crossref database and provides links to scihub.
:param ctx: The `ctx` parameter is typically used in Discord.py, a Python library for creating Discord bots.
It represents the context of the command being executed, including information about the message, the server,
and the user who invoked the command.
"""
# TODO: Implement deep search logic here
query = ctx.message.content.replace("$glebokie_gardlo", "")
allowed = False
for role in ctx.message.author.roles:
if role.name == "Bartender":
allowed = True
if role.name == "Scribe":
allowed = True
if role.name == "Thane":
allowed = True
if not allowed:
if ctx.message.author.nick:
username = ctx.message.author.nick
else:
username = ctx.message.author.name
vykidailo = False
bartender = False
prompt = "Przygotuj mi drinka o nazwie Głębokie Gardło, inspirowanego tym sławnym filmem oraz skandalem Watergate"
for role in ctx.message.author.roles:
if role.name == "Vykidailo":
vykidailo = True
if role.name == "Bartender":
bartender = True
global MESSAGE_TABLE # pylint: disable=global-statement
result, MESSAGE_TABLE = await handle_response(
prompt, vykidailo, bartender, MESSAGE_TABLE, username, "GENERAL"
)
if len(result) < 1500:
await ctx.send(result)
else:
while len(result) > 1500:
await ctx.send(result[:1500])
result = result[1500:]
return
query_uuid = uuid.uuid4()
# TODO: TESTING ONLY!!
# query_uuid = uuid.UUID('{12345678-1234-5678-1234-567812345678}')
json_query = {
"UUID": str(query_uuid),
"query": str(query),
"page": 1,
"deep_search": True,
}
coroutine = asyncio.to_thread(
requests.post,
f"{LIBRARIAN_SERVICE_ADDRESS}{SEND_QUERY}",
json=json_query,
headers=SERVICE_HEADERS,
timeout=360,
)
await ctx.send(
"*Conjurer mruga okiem i zamiast drinka wyjmuje dysk usb z terminala. Podchodzi do sprytnie ukrytej przy barze rury od poczty pneumatycznej i"
+ " wrzuca ten dysk do środk* To teraz trza poczekać kilka godzin. TO będzie głębokie wyszukanie"
+ " Rozgląda się dookoła i stawia przed tobą mętnego drinka o zapachu mięty, gwiezdnego pyłu i oleju silnikowego"
)
query_response = await coroutine
if not query_response.status_code == 200:
await ctx.send(
"*Z rury wydobywa się dym. Conjurer łapie pierwszą ciecz pod ręką i pryska na rurę. Następuje drobna eksplozja i wszystko zaczyna się palić."
+ " Conjurer jest skonfundowany..* Wołaj szefa - mam nieodparte wrażenie że się coś wyjebało"
)
return
query, query_uuid, queue_size = (
query_response.json()["data"][0],
query_response.json()["data"][1],
query_response.json()["data"][2],
)
if ctx.message.author.nick:
username = ctx.message.author.nick
else:
username = ctx.message.author.name
query_object = QueryControl(username, query_uuid, query, ctx)
OUT_COMM_Q.put(query_object)
await ctx.send(
f"Wypij wypi {query_uuid} - to identyfikator twojego zapytania. Jesteś {queue_size} w kolejce niestety kolejka obowiazuje zawsze."
+ " Zapytania obsługuje algorytm zasilany czterema chomikami zapierdalającymi w kołowrotku - więc wyniki najwcześniej za kilka godzin - ale mogą być też dni. Głębokie zabawy trwają dłużej. *Znowu mruga*"
)
async def setup(bot):
logger = logging.getLogger("discord")
dm = DataModule(bot, "discord")
dm.check_data_q.start()
await bot.add_cog(dm)
logger.info("Loading data sharing commands module done")

Some files were not shown because too many files have changed in this diff Show More