+17
@@ -0,0 +1,17 @@
|
|||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*.egg-info/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.pytest_cache/
|
||||||
|
.mypy_cache/
|
||||||
|
.ruff_cache/
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# venv
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
|
||||||
|
# Projekt-spezifisch
|
||||||
|
create_selfsign/crt/
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#! /usr/bin/env python3.10
|
#! /usr/bin/env python3
|
||||||
|
|
||||||
import os, configparser
|
import os
|
||||||
|
import configparser
|
||||||
|
|
||||||
# Set Skript Vars
|
# Set Skript Vars
|
||||||
user_gitconfig = os.environ["HOME"] + os.sep + ".gitconfig"
|
user_gitconfig = os.environ["HOME"] + os.sep + ".gitconfig"
|
||||||
@@ -51,14 +52,14 @@ if not config_ini.has_section("alias"):
|
|||||||
for my_git_site in list_my_git_projects:
|
for my_git_site in list_my_git_projects:
|
||||||
if not config_ini.has_section("credential " + '"' + my_git_site + '"'):
|
if not config_ini.has_section("credential " + '"' + my_git_site + '"'):
|
||||||
config_ini.add_section("credential " + '"' + my_git_site + '"')
|
config_ini.add_section("credential " + '"' + my_git_site + '"')
|
||||||
config_ini.set("credential " + '"' + my_git_site + '"', "username", my_username)
|
config_ini.set("credential " + '"' + my_git_site +
|
||||||
|
'"', "username", my_username)
|
||||||
|
|
||||||
if not config_ini.has_section("URL " + '"' + my_git_site + '"'):
|
if not config_ini.has_section("URL " + '"' + my_git_site + '"'):
|
||||||
config_ini.add_section("URL " + '"' + my_git_site + '"')
|
config_ini.add_section("URL " + '"' + my_git_site + '"')
|
||||||
config_ini.set("URL " + '"' + my_git_site + '"', "insteadOf", 'git@' + my_git_site + ":")
|
config_ini.set("URL " + '"' + my_git_site + '"',
|
||||||
|
"insteadOf", 'git@' + my_git_site + ":")
|
||||||
|
|
||||||
# writing_all_configs
|
# writing_all_configs
|
||||||
with open(user_gitconfig, "w") as configfile:
|
with open(user_gitconfig, "w") as configfile:
|
||||||
config_ini.write(configfile)
|
config_ini.write(configfile)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# selfsign_ca
|
||||||
|
|
||||||
|
CA-gestützte Erstellung selbst-signierter X.509-Zertifikate mit Python `cryptography`.
|
||||||
|
|
||||||
|
## Funktionsweise
|
||||||
|
|
||||||
|
Beim ersten Aufruf wird automatisch eine Root-CA erstellt (`crt/ca.key` + `crt/ca.crt`). Alle weiteren Zertifikate werden von dieser CA signiert. Existiert die CA bereits, wird sie wiederverwendet.
|
||||||
|
|
||||||
|
Jedes Zertifikat wird als Trio abgelegt:
|
||||||
|
|
||||||
|
| Datei | Inhalt |
|
||||||
|
|---|---|
|
||||||
|
| `crt/<name>.key` | RSA-2048 Private Key (PEM) |
|
||||||
|
| `crt/<name>.crt` | X.509-Zertifikat, signiert von der CA |
|
||||||
|
| `crt/<name>-chain.crt` | Server-Zertifikat + CA-Zertifikat (Chain) |
|
||||||
|
|
||||||
|
## Abhängigkeiten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install cryptography
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verwendung
|
||||||
|
|
||||||
|
### Direktaufruf
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python selfsign_ca.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Erzeugt eine CA (falls nicht vorhanden) und das Zertifikat `test.*` mit den im `__main__`-Block hinterlegten Defaults.
|
||||||
|
|
||||||
|
### Als Modul
|
||||||
|
|
||||||
|
```python
|
||||||
|
from selfsign_ca import generate_and_save_cert
|
||||||
|
|
||||||
|
generate_and_save_cert(
|
||||||
|
cert_country="DE",
|
||||||
|
cert_state="Berlin",
|
||||||
|
cert_organization="Meine GmbH",
|
||||||
|
cert_locality="Berlin",
|
||||||
|
cert_organizational_unit="IT",
|
||||||
|
cert_common_name="myserver.local",
|
||||||
|
valid_days=365,
|
||||||
|
serial_number=100,
|
||||||
|
cert_name="myserver",
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### CA-Parameter (optional)
|
||||||
|
|
||||||
|
Die CA-Daten werden nur beim ersten Erstellen der CA verwendet. Überschreiben via:
|
||||||
|
|
||||||
|
```python
|
||||||
|
generate_and_save_cert(
|
||||||
|
...,
|
||||||
|
ca_country="DE",
|
||||||
|
ca_state="Sachsen",
|
||||||
|
ca_organization="IchAG",
|
||||||
|
ca_locality="Dresden",
|
||||||
|
ca_common_name="My Root CA",
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Zertifikat prüfen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openssl verify -CAfile crt/ca.crt crt/<name>.crt
|
||||||
|
openssl x509 -in crt/<name>.crt -text -noout
|
||||||
|
```
|
||||||
|
|
||||||
|
## CA auf Clients importieren (Vertrauen)
|
||||||
|
|
||||||
|
Damit Clients dem Zertifikat vertrauen, muss `crt/ca.crt` im Trust-Store hinterlegt werden:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Arch/Manjaro
|
||||||
|
sudo trust anchor crt/ca.crt
|
||||||
|
|
||||||
|
# Debian/Ubuntu
|
||||||
|
sudo cp crt/ca.crt /usr/local/share/ca-certificates/my-ca.crt
|
||||||
|
sudo update-ca-certificates
|
||||||
|
```
|
||||||
|
|
||||||
|
## Technische Details
|
||||||
|
|
||||||
|
- **CA**: RSA 4096 Bit, SHA256, 10 Jahre gültig, `basicConstraints: CA:TRUE`
|
||||||
|
- **Endzertifikat**: RSA 2048 Bit, SHA256, Gültigkeit nach `valid_days`, `basicConstraints: CA:FALSE`
|
||||||
|
- X.509 v3 Extensions: `BasicConstraints`, `KeyUsage`, `SubjectKeyIdentifier`, `AuthorityKeyIdentifier`
|
||||||
|
- Alle Dateien landen im Unterverzeichnis `crt/` (wird automatisch angelegt)
|
||||||
Executable
+218
@@ -0,0 +1,218 @@
|
|||||||
|
import os
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
|
|
||||||
|
from cryptography import x509
|
||||||
|
from cryptography.x509.oid import NameOID
|
||||||
|
from cryptography.hazmat.primitives import hashes, serialization
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||||
|
|
||||||
|
|
||||||
|
CRT_DIR = "crt"
|
||||||
|
CA_KEY_FILE = os.path.join(CRT_DIR, "ca.key")
|
||||||
|
CA_CRT_FILE = os.path.join(CRT_DIR, "ca.crt")
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_crt_dir():
|
||||||
|
"""Create crt/ directory if it doesn't exist."""
|
||||||
|
os.makedirs(CRT_DIR, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _save_pem(filename, data):
|
||||||
|
"""Write PEM data to file, converting \\n to real newlines."""
|
||||||
|
if isinstance(data, bytes):
|
||||||
|
data = data.decode()
|
||||||
|
with open(filename, "w") as f:
|
||||||
|
for line in data.replace("\r", "").split("\\n"):
|
||||||
|
f.write(line + "\n")
|
||||||
|
|
||||||
|
|
||||||
|
def _build_subject(country, state, organization, locality, common_name,
|
||||||
|
organizational_unit=None):
|
||||||
|
"""Build a cryptography X.509 Name from individual fields."""
|
||||||
|
attrs = [
|
||||||
|
x509.NameAttribute(NameOID.COUNTRY_NAME, country),
|
||||||
|
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, state),
|
||||||
|
x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization),
|
||||||
|
x509.NameAttribute(NameOID.LOCALITY_NAME, locality),
|
||||||
|
x509.NameAttribute(NameOID.COMMON_NAME, common_name),
|
||||||
|
]
|
||||||
|
if organizational_unit:
|
||||||
|
attrs.append(x509.NameAttribute(
|
||||||
|
NameOID.ORGANIZATIONAL_UNIT_NAME, organizational_unit))
|
||||||
|
return x509.Name(attrs)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_ca_cert(cert_country, cert_state, cert_organization,
|
||||||
|
cert_locality, cert_common_name, valid_days=3650):
|
||||||
|
"""
|
||||||
|
Generate a self-signed CA certificate and save ca.key / ca.crt.
|
||||||
|
Returns (cert_pem, key_pem).
|
||||||
|
"""
|
||||||
|
subject = _build_subject(cert_country, cert_state, cert_organization,
|
||||||
|
cert_locality, cert_common_name)
|
||||||
|
|
||||||
|
private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096)
|
||||||
|
|
||||||
|
now = datetime.now(timezone.utc)
|
||||||
|
cert = (
|
||||||
|
x509.CertificateBuilder()
|
||||||
|
.subject_name(subject)
|
||||||
|
.issuer_name(subject) # self-signed
|
||||||
|
.public_key(private_key.public_key())
|
||||||
|
.serial_number(1)
|
||||||
|
.not_valid_before(now)
|
||||||
|
.not_valid_after(now + timedelta(days=valid_days))
|
||||||
|
.add_extension(x509.BasicConstraints(ca=True, path_length=None),
|
||||||
|
critical=True)
|
||||||
|
.add_extension(x509.KeyUsage(
|
||||||
|
key_cert_sign=True, crl_sign=True,
|
||||||
|
digital_signature=False, content_commitment=False,
|
||||||
|
key_encipherment=False, data_encipherment=False,
|
||||||
|
key_agreement=False, encipher_only=False, decipher_only=False,
|
||||||
|
), critical=True)
|
||||||
|
.add_extension(x509.SubjectKeyIdentifier.from_public_key(
|
||||||
|
private_key.public_key()), critical=False)
|
||||||
|
.sign(private_key, hashes.SHA256())
|
||||||
|
)
|
||||||
|
|
||||||
|
cert_pem = cert.public_bytes(serialization.Encoding.PEM)
|
||||||
|
key_pem = private_key.private_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
||||||
|
encryption_algorithm=serialization.NoEncryption(),
|
||||||
|
)
|
||||||
|
|
||||||
|
_ensure_crt_dir()
|
||||||
|
_save_pem(CA_KEY_FILE, key_pem)
|
||||||
|
_save_pem(CA_CRT_FILE, cert_pem)
|
||||||
|
|
||||||
|
print(f"CA erstellt: {CA_KEY_FILE}, {CA_CRT_FILE}")
|
||||||
|
return cert_pem, key_pem
|
||||||
|
|
||||||
|
|
||||||
|
def load_ca():
|
||||||
|
"""
|
||||||
|
Load CA certificate and private key from disk.
|
||||||
|
Returns (ca_cert, ca_pkey) as cryptography objects, or None if missing.
|
||||||
|
"""
|
||||||
|
if not os.path.exists(CA_CRT_FILE) or not os.path.exists(CA_KEY_FILE):
|
||||||
|
return None
|
||||||
|
|
||||||
|
with open(CA_CRT_FILE, "rb") as f:
|
||||||
|
ca_cert = x509.load_pem_x509_certificate(f.read())
|
||||||
|
with open(CA_KEY_FILE, "rb") as f:
|
||||||
|
ca_pkey = serialization.load_pem_private_key(f.read(), password=None)
|
||||||
|
|
||||||
|
return ca_cert, ca_pkey
|
||||||
|
|
||||||
|
|
||||||
|
def generate_cert_signed_by_ca(ca_cert, ca_pkey,
|
||||||
|
cert_country, cert_state, cert_organization,
|
||||||
|
cert_locality, cert_organizational_unit,
|
||||||
|
cert_common_name, valid_days, serial_number):
|
||||||
|
"""
|
||||||
|
Generate a certificate signed by the given CA.
|
||||||
|
Returns (cert_pem, key_pem) as strings.
|
||||||
|
"""
|
||||||
|
subject = _build_subject(cert_country, cert_state, cert_organization,
|
||||||
|
cert_locality, cert_common_name,
|
||||||
|
cert_organizational_unit)
|
||||||
|
|
||||||
|
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||||
|
|
||||||
|
now = datetime.now(timezone.utc)
|
||||||
|
cert = (
|
||||||
|
x509.CertificateBuilder()
|
||||||
|
.subject_name(subject)
|
||||||
|
.issuer_name(ca_cert.subject)
|
||||||
|
.public_key(private_key.public_key())
|
||||||
|
.serial_number(serial_number)
|
||||||
|
.not_valid_before(now)
|
||||||
|
.not_valid_after(now + timedelta(days=valid_days))
|
||||||
|
.add_extension(x509.BasicConstraints(ca=False, path_length=None),
|
||||||
|
critical=True)
|
||||||
|
.add_extension(x509.KeyUsage(
|
||||||
|
digital_signature=True, key_encipherment=True,
|
||||||
|
key_cert_sign=False, crl_sign=False,
|
||||||
|
content_commitment=False, data_encipherment=False,
|
||||||
|
key_agreement=False, encipher_only=False, decipher_only=False,
|
||||||
|
), critical=True)
|
||||||
|
.add_extension(x509.SubjectKeyIdentifier.from_public_key(
|
||||||
|
private_key.public_key()), critical=False)
|
||||||
|
.add_extension(x509.AuthorityKeyIdentifier.from_issuer_public_key(
|
||||||
|
ca_pkey.public_key()), critical=False)
|
||||||
|
.sign(ca_pkey, hashes.SHA256())
|
||||||
|
)
|
||||||
|
|
||||||
|
cert_pem = cert.public_bytes(serialization.Encoding.PEM)
|
||||||
|
key_pem = private_key.private_bytes(
|
||||||
|
encoding=serialization.Encoding.PEM,
|
||||||
|
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
||||||
|
encryption_algorithm=serialization.NoEncryption(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return str(cert_pem.decode()), str(key_pem.decode())
|
||||||
|
|
||||||
|
|
||||||
|
def generate_and_save_cert(cert_country, cert_state, cert_organization,
|
||||||
|
cert_locality, cert_organizational_unit,
|
||||||
|
cert_common_name, valid_days=365, serial_number=100,
|
||||||
|
ca_country="DE", ca_state="Sachsen",
|
||||||
|
ca_organization="IchAG",
|
||||||
|
ca_locality="Dresden",
|
||||||
|
ca_common_name="My Root CA",
|
||||||
|
cert_name="server"):
|
||||||
|
"""
|
||||||
|
High-level entry point:
|
||||||
|
1. If CA not present, create it.
|
||||||
|
2. Generate certificate signed by the CA.
|
||||||
|
3. Save key and cert (with optional chain) to <cert_name>.key / <cert_name>.crt.
|
||||||
|
"""
|
||||||
|
ca = load_ca()
|
||||||
|
if ca is None:
|
||||||
|
print("CA nicht gefunden – erstelle CA ...")
|
||||||
|
generate_ca_cert(ca_country, ca_state, ca_organization,
|
||||||
|
ca_locality, ca_common_name)
|
||||||
|
ca = load_ca()
|
||||||
|
if ca is None:
|
||||||
|
raise RuntimeError("CA konnte nicht erstellt/geladen werden.")
|
||||||
|
|
||||||
|
ca_cert, ca_pkey = ca
|
||||||
|
|
||||||
|
cert_pem, key_pem = generate_cert_signed_by_ca(
|
||||||
|
ca_cert, ca_pkey,
|
||||||
|
cert_country, cert_state, cert_organization,
|
||||||
|
cert_locality, cert_organizational_unit,
|
||||||
|
cert_common_name, valid_days, serial_number,
|
||||||
|
)
|
||||||
|
|
||||||
|
key_file = os.path.join(CRT_DIR, f"{cert_name}.key")
|
||||||
|
crt_file = os.path.join(CRT_DIR, f"{cert_name}.crt")
|
||||||
|
chain_file = os.path.join(CRT_DIR, f"{cert_name}-chain.crt")
|
||||||
|
|
||||||
|
_ensure_crt_dir()
|
||||||
|
_save_pem(key_file, key_pem)
|
||||||
|
_save_pem(crt_file, cert_pem)
|
||||||
|
|
||||||
|
# Chain file: server cert + CA cert
|
||||||
|
chain = cert_pem.replace("\r", "")
|
||||||
|
ca_pem = ca_cert.public_bytes(serialization.Encoding.PEM).decode()
|
||||||
|
chain += "\n" + ca_pem
|
||||||
|
_save_pem(chain_file, chain)
|
||||||
|
|
||||||
|
print(f"Zertifikat erstellt: {key_file}, {crt_file}, {chain_file}")
|
||||||
|
return cert_pem, key_pem
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
generate_and_save_cert(
|
||||||
|
cert_country="DE",
|
||||||
|
cert_state="Dresden",
|
||||||
|
cert_organization="IchAG",
|
||||||
|
cert_locality="Sachsen",
|
||||||
|
cert_organizational_unit="mandan01",
|
||||||
|
cert_common_name="mandan01",
|
||||||
|
valid_days=365,
|
||||||
|
serial_number=12,
|
||||||
|
cert_name="test",
|
||||||
|
)
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
from OpenSSL import crypto
|
|
||||||
from Crypto.PublicKey import RSA
|
|
||||||
|
|
||||||
|
|
||||||
def generate_self_signed_cert(cert_country, cert_state, cert_organization,
|
|
||||||
cert_locality, cert_organizational_unit,
|
|
||||||
cert_common_name, valid_days, serial_number):
|
|
||||||
rsa_key = RSA.generate(2048)
|
|
||||||
|
|
||||||
pk = crypto.load_privatekey(crypto.FILETYPE_PEM,
|
|
||||||
rsa_key.exportKey('PEM', pkcs=1))
|
|
||||||
cert = crypto.X509()
|
|
||||||
sub = cert.get_subject()
|
|
||||||
sub.CN = cert_common_name
|
|
||||||
sub.C = cert_country
|
|
||||||
sub.ST = cert_state
|
|
||||||
sub.L = cert_locality
|
|
||||||
sub.O = cert_organization
|
|
||||||
|
|
||||||
# optional
|
|
||||||
if cert_organizational_unit:
|
|
||||||
sub.OU = cert_organizational_unit
|
|
||||||
|
|
||||||
cert.set_serial_number(serial_number)
|
|
||||||
cert.gmtime_adj_notBefore(0)
|
|
||||||
cert.gmtime_adj_notAfter(valid_days * 24 * 60 * 60) # Valid for a year
|
|
||||||
cert.set_issuer(sub)
|
|
||||||
cert.set_pubkey(pk)
|
|
||||||
cert.sign(pk, 'sha1')
|
|
||||||
|
|
||||||
cert_text = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
|
|
||||||
priv_key_text = rsa_key.exportKey('PEM', pkcs=1)
|
|
||||||
|
|
||||||
return str(cert_text), str(priv_key_text)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
test = generate_self_signed_cert(cert_country="DE", cert_state="Dresden", cert_organization="IchAG", cert_locality="Sachsen", cert_organizational_unit="mandan01", cert_common_name="mandan01", valid_days=365, serial_number=12)
|
|
||||||
privatekey = test[1].rstrip("'").strip("b'")
|
|
||||||
cert = test[0].rstrip("'").strip("b'")
|
|
||||||
#print(privatekey)
|
|
||||||
for key in privatekey.split("\\n"):
|
|
||||||
with open("testkey", "a") as testcert:
|
|
||||||
print(key, file=testcert)
|
|
||||||
for cert_out in cert.split("\\n"):
|
|
||||||
with open("testcert", "a") as testcert_out:
|
|
||||||
print(cert_out, file=testcert_out)
|
|
||||||
|
|
||||||
#test2 = "xccj\njdkjd\n"
|
|
||||||
#print(test2)
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 5,
|
||||||
|
"id": "70914fb0-e3d4-4233-ad33-70a1a2517a6b",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import os"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 7,
|
||||||
|
"id": "b04d189c-260b-427d-af65-9ad88ac5ecf2",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"['.bash_logout', '.bash_profile', '.bashrc', '.zshrc', '.config', '.Xclients', '.dir_colors', '.profile', '.zshenv', '.local', 'Schreibtisch', 'Downloads', 'Vorlagen', 'Öffentlich', 'Dokumente', 'Musik', 'Bilder', 'Videos', '.cache', '.mozilla', '.lyrics', '.gemini', 'my_sway_konfig', 'Projekte', '.ansible', '.ssh', '.vim', '.tmux.conf', '.npm', 'create_lxc', 'lxc_folder', '.docker', 'ebook', '.bash_history', '.zhistory', 'Nextcloud', '.yarn', '.pki', 'sonovum', '.wget-hsts', '.joplin', 'JoplinBackup', '.python_history', '.gnupg', '.gitconfig', '.gitignore', '.env', '.ollama', '.claude', '.steam', '.pulse-cookie', '.icons', 'cert', 'podcast-studio', 'scripts', 'Screenshots', '.claude.json.backup.1772740061126', '.claude.json.backup.1772740061140', '.claude.json.backup.1772740137318', '.claude.json.backup.1772740278244', '.claude.json.backup.1772740278252', '.claude.json', 'Media-Data', '.smbcredentials-media', 'nfs', '.mplayer', '.steampath', '.steampid', '.eclipse', '.swt', '.java', 'conf.ini', 'token_vaultwarden', 'jenkins_status_example', '.sigstore', 'tinydb_vs_sqlite.md', '.cargo', '.viminfo', '.ipython', '.jupyter']\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"print(os.listdir(\"/home/jonnybravo/\"))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 13,
|
||||||
|
"id": "55709fef-1402-4c9f-b2ee-2be8e55a137c",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"['ver_next_einbinden.md', 'yubikey_setup_guide.md', 'networkconfig_dns.md', 'blueray_install_manjaro.md', 'calcurse_tastenkürzel.md', 'Stretchen_laufen.md']\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"all_files_with_md = [ x for x in os.listdir(\"/home/jonnybravo/Dokumente\") if x.endswith(\".md\") ]\n",
|
||||||
|
"print(all_files_with_md)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "89b5f549-36c9-4a62-83ba-69ad84ec6be6",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "692cc39e-ddf8-4bcb-ad08-baed47e37a74",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3 (ipykernel)",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.14.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 5
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#! /usr/bin/env Python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
class create_unit_service():
|
||||||
|
def __init__(self, UnitName = str,systemd_sysfolder = "/etc/systemd/system", execstart = str, systemd_type = "simple") -> None:
|
||||||
|
self.UnitName = UnitName
|
||||||
|
self.systemd_systemfolder = systemd_sysfolder
|
||||||
|
self.execstart = execstart
|
||||||
|
if systemd_type == "simple" or systemd_type == "oneshot":
|
||||||
|
self.systemd_type = systemd_type
|
||||||
|
else:
|
||||||
|
print("Kein richtiger Typ")
|
||||||
|
raise "systemd_type ist nicht richtig"
|
||||||
|
|
||||||
|
def create_unit(self):
|
||||||
|
UnitFile = self.systemd_systemfolder + os.sep + self.UnitName + ".service"
|
||||||
|
if os.path.exists(self.systemd_systemfolder):
|
||||||
|
if os.path.exists(UnitFile):
|
||||||
|
print("Gibt es bereits")
|
||||||
|
else:
|
||||||
|
print("Wird angelegt !!")
|
||||||
|
with open(UnitFile, "w") as ufile:
|
||||||
|
print("[Unit]",
|
||||||
|
"[Service]",
|
||||||
|
"Type=oneshot",
|
||||||
|
"PrivateTmp=yes",
|
||||||
|
"DynamicUser=yes",
|
||||||
|
"ExecStart={my_execStart}".format(my_execStart=self.execstart), file=ufile, sep="\n")
|
||||||
|
os.popen("systemctl daemon-reload")
|
||||||
|
|
||||||
|
def delete_unit(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
new_unit = create_unit_service(UnitName="TestUnit",
|
||||||
|
execstart="""/usr/bin/echo "Ich bin eine TestUnit %p" """,
|
||||||
|
systemd_type="oneshot")
|
||||||
|
new_unit.create_unit()
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
print(os.listdir("/home/jonnybravo/"))
|
||||||
|
|
||||||
|
|
||||||
|
all_files_with_md = [ x for x in os.listdir("/home/jonnybravo/Dokumente") if x.endswith(".md") ]
|
||||||
|
print(all_files_with_md)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 5,
|
||||||
|
"id": "70914fb0-e3d4-4233-ad33-70a1a2517a6b",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import os"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 7,
|
||||||
|
"id": "b04d189c-260b-427d-af65-9ad88ac5ecf2",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"['.bash_logout', '.bash_profile', '.bashrc', '.zshrc', '.config', '.Xclients', '.dir_colors', '.profile', '.zshenv', '.local', 'Schreibtisch', 'Downloads', 'Vorlagen', 'Öffentlich', 'Dokumente', 'Musik', 'Bilder', 'Videos', '.cache', '.mozilla', '.lyrics', '.gemini', 'my_sway_konfig', 'Projekte', '.ansible', '.ssh', '.vim', '.tmux.conf', '.npm', 'create_lxc', 'lxc_folder', '.docker', 'ebook', '.bash_history', '.zhistory', 'Nextcloud', '.yarn', '.pki', 'sonovum', '.wget-hsts', '.joplin', 'JoplinBackup', '.python_history', '.gnupg', '.gitconfig', '.gitignore', '.env', '.ollama', '.claude', '.steam', '.pulse-cookie', '.icons', 'cert', 'podcast-studio', 'scripts', 'Screenshots', '.claude.json.backup.1772740061126', '.claude.json.backup.1772740061140', '.claude.json.backup.1772740137318', '.claude.json.backup.1772740278244', '.claude.json.backup.1772740278252', '.claude.json', 'Media-Data', '.smbcredentials-media', 'nfs', '.mplayer', '.steampath', '.steampid', '.eclipse', '.swt', '.java', 'conf.ini', 'token_vaultwarden', 'jenkins_status_example', '.sigstore', 'tinydb_vs_sqlite.md', '.cargo', '.viminfo', '.ipython', '.jupyter']\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"print(os.listdir(\"/home/jonnybravo/\"))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 13,
|
||||||
|
"id": "55709fef-1402-4c9f-b2ee-2be8e55a137c",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"['ver_next_einbinden.md', 'yubikey_setup_guide.md', 'networkconfig_dns.md', 'blueray_install_manjaro.md', 'calcurse_tastenkürzel.md', 'Stretchen_laufen.md']\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"all_files_with_md = [ x for x in os.listdir(\"/home/jonnybravo/Dokumente\") if x.endswith(\".md\") ]\n",
|
||||||
|
"print(all_files_with_md)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "89b5f549-36c9-4a62-83ba-69ad84ec6be6",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "692cc39e-ddf8-4bcb-ad08-baed47e37a74",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3 (ipykernel)",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.14.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 5
|
||||||
|
}
|
||||||
+51
-11
@@ -1,12 +1,34 @@
|
|||||||
#! /usr/bin/env Python3
|
#! /usr/bin/env Python3
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from posix import stat
|
||||||
|
from jinja2 import Template
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def is_root():
|
||||||
|
if os.geteuid() == 0:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
class create_unit_service():
|
class create_unit_service():
|
||||||
def __init__(self, UnitName = str,systemd_sysfolder = "/etc/systemd/system", execstart = str, systemd_type = "simple") -> None:
|
def __init__(self,
|
||||||
|
UnitName: str,
|
||||||
|
systemd_sysfolder: str = "/etc/systemd/system",
|
||||||
|
UnitExecStart = str,
|
||||||
|
systemd_type: str = "simple",
|
||||||
|
UnitDescription: str = "Meine Unit",
|
||||||
|
UnitUser = str,
|
||||||
|
UnitWorkDir: str = "/home/jonnybravo/"
|
||||||
|
) -> None:
|
||||||
|
|
||||||
self.UnitName = UnitName
|
self.UnitName = UnitName
|
||||||
self.systemd_systemfolder = systemd_sysfolder
|
self.systemd_systemfolder = systemd_sysfolder
|
||||||
self.execstart = execstart
|
self.UnitExecStart = UnitExecStart
|
||||||
|
self.UnitDescription = UnitDescription
|
||||||
|
self.UnitWorkDir = UnitWorkDir
|
||||||
|
self.UnitUser = UnitUser
|
||||||
if systemd_type == "simple" or systemd_type == "oneshot":
|
if systemd_type == "simple" or systemd_type == "oneshot":
|
||||||
self.systemd_type = systemd_type
|
self.systemd_type = systemd_type
|
||||||
else:
|
else:
|
||||||
@@ -20,20 +42,38 @@ class create_unit_service():
|
|||||||
print("Gibt es bereits")
|
print("Gibt es bereits")
|
||||||
else:
|
else:
|
||||||
print("Wird angelegt !!")
|
print("Wird angelegt !!")
|
||||||
with open(UnitFile, "w") as ufile:
|
with open('template/LinuxUnit.j2') as f:
|
||||||
print("[Unit]",
|
tmpl = Template(f.read())
|
||||||
"[Service]",
|
with open(UnitFile, "w") as uf:
|
||||||
"Type=oneshot",
|
print(tmpl.render(
|
||||||
"PrivateTmp=yes",
|
description = self.UnitDescription,
|
||||||
"DynamicUser=yes",
|
working_dir = self.UnitWorkDir,
|
||||||
"ExecStart={my_execStart}".format(my_execStart=self.execstart), file=ufile, sep="\n")
|
exec_command = self.UnitExecStart,
|
||||||
os.popen("systemctl daemon-reload")
|
user = self.UnitUser,
|
||||||
|
env_vars = {"PYTHONPATH": "."},
|
||||||
|
service_type = self.systemd_type
|
||||||
|
),file=uf)
|
||||||
|
|
||||||
|
def unit_start_and_load(self):
|
||||||
|
UnitFile = self.systemd_systemfolder + os.sep + self.UnitName + ".service"
|
||||||
|
status_daemon_reload = subprocess.run(["systemctl", "daemon-reload"])
|
||||||
|
if status_daemon_reload.returncode != 0:
|
||||||
|
raise Exception( f'Systemd reload Invalid result: { status_daemon_reload.returncode }' )
|
||||||
|
else:
|
||||||
|
print(f"{self.UnitName} wurde angelegt und kann genutzt werden !!! Ein starten oder Enable wurde bewusst nicht eingebaut.")
|
||||||
|
|
||||||
def delete_unit(self):
|
def delete_unit(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
if is_root():
|
||||||
new_unit = create_unit_service(UnitName="TestUnit",
|
new_unit = create_unit_service(UnitName="TestUnit",
|
||||||
execstart="""/usr/bin/echo "Ich bin eine TestUnit %p" """,
|
UnitExecStart="""/usr/bin/echo "Ich bin eine TestUnit %p" """,
|
||||||
|
UnitUser="jonnybravo",
|
||||||
systemd_type="oneshot")
|
systemd_type="oneshot")
|
||||||
new_unit.create_unit()
|
new_unit.create_unit()
|
||||||
|
new_unit.unit_start_and_load()
|
||||||
|
else:
|
||||||
|
print("Du bist nicht root führe das Skript mit sudo aus")
|
||||||
|
print('sudo python <skript>')
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
- systemd reload
|
||||||
|
- systemd start
|
||||||
|
- systemd enable
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
[Unit]
|
||||||
|
Description={{ description }}
|
||||||
|
# Stellt sicher, dass das Netzwerk bereit ist
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
# 'simple' ist der Standard, 'exec' wartet, bis der Prozess wirklich gestartet ist
|
||||||
|
Type={{ service_type }}
|
||||||
|
|
||||||
|
# Arbeitsverzeichnis (wichtig für relative Pfade im Skript)
|
||||||
|
WorkingDirectory={{ working_dir }}
|
||||||
|
|
||||||
|
# Ausführen als spezifischer Benutzer (Sicherheit!)
|
||||||
|
User={{ user }}
|
||||||
|
Group={{ user }}
|
||||||
|
|
||||||
|
# Umgebungsvariablen (z.B. für Python Pfade oder API Keys)
|
||||||
|
{% if env_vars -%}
|
||||||
|
{% for key, value in env_vars.items() -%}
|
||||||
|
Environment="{{ key }}={{ value }}"
|
||||||
|
{% endfor -%}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
# Vor dem Start kurz warten (optional, falls nötig)
|
||||||
|
{% if wait_before_start -%}
|
||||||
|
ExecStartPre=/usr/bin/sleep {{ wait_before_start }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
# Der eigentliche Befehl
|
||||||
|
ExecStart={{ exec_command }}
|
||||||
|
|
||||||
|
# Neustart-Logik: Startet den Dienst automatisch neu, wenn er abstürzt
|
||||||
|
Restart=on-failure
|
||||||
|
# Wartezeit zwischen Neustartversuchen
|
||||||
|
RestartSec=5s
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
# Definiert, wann die Unit beim Booten gestartet wird
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Benötigt die Installation von 'requests' und 'beautifulsoup4'
|
||||||
|
# pip install requests beautifulsoup4
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
def suche_film_url(film_titel):
|
||||||
|
"""
|
||||||
|
Sucht auf IMDb nach einem Film und gibt die deutsche URL der Filmseite zurück.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
film_titel: Der Titel des Films, nach dem gesucht werden soll.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Die deutsche URL der Filmseite oder None, wenn nichts gefunden wurde.
|
||||||
|
"""
|
||||||
|
such_url = f"https://www.imdb.com/find?q={film_titel.replace(' ', '+')}"
|
||||||
|
# Header, um die deutsche Seite zu bevorzugen
|
||||||
|
headers = {
|
||||||
|
'Accept-Language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7',
|
||||||
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(such_url, headers=headers)
|
||||||
|
response.raise_for_status() # Löst eine Ausnahme für HTTP-Fehler aus
|
||||||
|
|
||||||
|
soup = BeautifulSoup(response.text, 'html.parser')
|
||||||
|
|
||||||
|
# Finden des ersten Links im Titel-Ergebnisbereich
|
||||||
|
ergebnis_bereich = soup.find('section', {'data-testid': 'find-results-section-title'})
|
||||||
|
if ergebnis_bereich:
|
||||||
|
link_tag = ergebnis_bereich.find('a', href=re.compile(r'/title/tt\d+'))
|
||||||
|
if link_tag and 'href' in link_tag.attrs:
|
||||||
|
pfad = link_tag['href']
|
||||||
|
# Extrahieren der Titel-ID (z.B. tt0133093)
|
||||||
|
match = re.search(r'(tt\d+)', pfad)
|
||||||
|
if match:
|
||||||
|
titel_id = match.group(1)
|
||||||
|
return f"https://www.imdb.com/de/title/{titel_id}"
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f"Ein Fehler bei der Anfrage ist aufgetreten: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
film_name = " ".join(sys.argv[1:])
|
||||||
|
url = suche_film_url(film_name)
|
||||||
|
if url:
|
||||||
|
print(f"URL für '{film_name}' gefunden: {url}")
|
||||||
|
else:
|
||||||
|
print(f"Konnte keinen Film mit dem Titel '{film_name}' finden.")
|
||||||
|
else:
|
||||||
|
print("Benutzung: python imdb_suche.py <film_titel>")
|
||||||
Executable
+99
@@ -0,0 +1,99 @@
|
|||||||
|
|
||||||
|
import urllib.request
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import ssl
|
||||||
|
import imdb_suche
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def get_movie_details(imdb_url):
|
||||||
|
"""
|
||||||
|
Ruft eine IMDb-Filmseite auf und extrahiert den Regisseur und die Hauptdarsteller.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
imdb_url (str): Die vollständige URL zur IMDb-Filmseite.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Ein Wörterbuch mit "director" und "actors" oder None bei einem Fehler.
|
||||||
|
"""
|
||||||
|
if not re.match(r"https://www.imdb.com/de/title/tt\d+/?", imdb_url):
|
||||||
|
print("Fehler: Ungültige IMDb-URL. Die URL sollte so aussehen: https://www.imdb.com/title/tt...")
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# SSL-Kontext erstellen, um Zertifikatsüberprüfungsfehler zu umgehen
|
||||||
|
context = ssl._create_unverified_context()
|
||||||
|
|
||||||
|
# User-Agent setzen, um wie ein Browser auszusehen und Blockaden zu vermeiden
|
||||||
|
headers = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}
|
||||||
|
|
||||||
|
req = urllib.request.Request(imdb_url, headers=headers)
|
||||||
|
|
||||||
|
with urllib.request.urlopen(req, context=context) as response:
|
||||||
|
html_content = response.read().decode('utf-8')
|
||||||
|
|
||||||
|
# Suchen Sie nach dem strukturierten Datenblock (JSON-LD), der Filminformationen enthält
|
||||||
|
match = re.search(
|
||||||
|
r'<script type="application/ld\+json">(.*?)</script>', html_content, re.DOTALL)
|
||||||
|
|
||||||
|
if not match:
|
||||||
|
print("Fehler: Konnte den JSON-LD-Datenblock auf der Seite nicht finden.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
json_data = json.loads(match.group(1))
|
||||||
|
|
||||||
|
# Extrahieren des Regisseurs
|
||||||
|
director = [d.get('name') for d in json_data.get('director', [])] if isinstance(
|
||||||
|
json_data.get('director'), list) else [json_data.get('director', {}).get('name')]
|
||||||
|
|
||||||
|
# Extrahieren der Schauspieler
|
||||||
|
actors = [a.get('name') for a in json_data.get('actor', [])]
|
||||||
|
|
||||||
|
# Extrahieren des Erscheinungsjahres
|
||||||
|
release_year = json_data.get('datePublished', '').split('-')[0]
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
"director": [d for d in director if d],
|
||||||
|
"actors": [a for a in actors if a],
|
||||||
|
"release_year": release_year
|
||||||
|
}
|
||||||
|
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(f"HTTP-Fehler beim Abrufen der URL: {e.code} {e.reason}")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ein Fehler ist aufgetreten: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
film_name = " ".join(sys.argv[1:])
|
||||||
|
url = imdb_suche.suche_film_url(film_name)
|
||||||
|
if url:
|
||||||
|
print(f"URL für '{film_name}' gefunden: {url}")
|
||||||
|
|
||||||
|
# Beispiel-URL für den Film "Inception"
|
||||||
|
# Du kannst jede andere IMDb-Film-URL hier einfügen
|
||||||
|
movie_url = url
|
||||||
|
|
||||||
|
print(f"Rufe Informationen für den Film ab: {movie_url}")
|
||||||
|
|
||||||
|
details = get_movie_details(movie_url)
|
||||||
|
|
||||||
|
if details:
|
||||||
|
print("\n--- Filminformationen ---")
|
||||||
|
print(f"Regisseur(e): {', '.join(details['director'])}")
|
||||||
|
# Zeigt die ersten 5 Schauspieler an
|
||||||
|
print(f"Hauptdarsteller: {', '.join(details['actors'][:5])}")
|
||||||
|
if details.get('release_year'):
|
||||||
|
print(f"Erscheinungsjahr: {details['release_year']}")
|
||||||
|
print("-------------------------")
|
||||||
|
else:
|
||||||
|
print(f"Konnte keinen Film mit dem Titel '{film_name}' finden.")
|
||||||
|
else:
|
||||||
|
print("Benutzung: python imdb_suche.py <film_titel>")
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
Folgende Punkte
|
|
||||||
|
|
||||||
- erstellen eine SQlite DB
|
|
||||||
- Die DB soll folgende Tabellen haben Genre, MyList,
|
|
||||||
- Die Anzeige soll über Flask angezeigt werden
|
|
||||||
|
|
||||||
Weitere Schritte folgen !!!
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
import DBcm
|
|
||||||
|
|
||||||
|
|
||||||
def create_movie_database(db_name="movie_db.db"):
|
|
||||||
|
|
||||||
create_my_list = """
|
|
||||||
create table if not exists movie_list (
|
|
||||||
id integer not null primary key autoincrement,
|
|
||||||
titel varchar(64) not null,
|
|
||||||
genre_id integer not null,
|
|
||||||
regie_id integer not null
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
create_genre = """
|
|
||||||
create table if not exists genre (
|
|
||||||
id integer not null primary key autoincrement,
|
|
||||||
name varchar(64) not null
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
create_regie = """
|
|
||||||
create table if not exists regie (
|
|
||||||
id integer not null primary key autoincrement,
|
|
||||||
surname varchar(64) not null,
|
|
||||||
lastname varchr(64) not null
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
create_medium = """
|
|
||||||
create table if not exists medium (
|
|
||||||
id integer not null primary key autoincrement,
|
|
||||||
medium varchar(64) not null
|
|
||||||
)
|
|
||||||
"""
|
|
||||||
|
|
||||||
with DBcm.UseDatabase(db_name) as db:
|
|
||||||
db.execute(create_my_list)
|
|
||||||
db.execute(create_genre)
|
|
||||||
db.execute(create_regie)
|
|
||||||
db.execute(create_medium)
|
|
||||||
|
|
||||||
|
|
||||||
def all_genres(db_name="movie_db.db"):
|
|
||||||
ALL_GENRE = "SELECT * from genre"
|
|
||||||
with DBcm.UseDatabase(db_name) as db:
|
|
||||||
db.execute(ALL_GENRE)
|
|
||||||
all_genre = [i[1] for i in db.fetchall()]
|
|
||||||
return all_genre
|
|
||||||
|
|
||||||
|
|
||||||
def search_genre_id(db_name="movie_db.db", genre_name=str):
|
|
||||||
GENRE_QUERY = """
|
|
||||||
select id from genre
|
|
||||||
where name = ?
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
with DBcm.UseDatabase(db_name) as db:
|
|
||||||
db.execute(GENRE_QUERY, (genre_name,))
|
|
||||||
genre_id = db.fetchone()[0]
|
|
||||||
return int(genre_id)
|
|
||||||
except:
|
|
||||||
return int(0)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
create_movie_database()
|
|
||||||
print(all_genres())
|
|
||||||
print(search_genre_id(genre_name="war"))
|
|
||||||
@@ -1,534 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 1,
|
|
||||||
"id": "5263a987-da36-46d7-a2e7-d0658cda09c1",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import DBcm"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 2,
|
|
||||||
"id": "3f6b0763-4106-4bfa-9aef-7afbd180c6d4",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"db_name = \"movie_db.db\"\n",
|
|
||||||
"\n",
|
|
||||||
"create_my_list = \"\"\"\n",
|
|
||||||
" create table if not exists movie_list (\n",
|
|
||||||
" id integer not null primary key autoincrement,\n",
|
|
||||||
" titel varchar(64) not null,\n",
|
|
||||||
" genre_id integer not null,\n",
|
|
||||||
" regie_id integer not null\n",
|
|
||||||
" \n",
|
|
||||||
" )\n",
|
|
||||||
"\n",
|
|
||||||
"\"\"\"\n",
|
|
||||||
"\n",
|
|
||||||
"create_genre = \"\"\"\n",
|
|
||||||
" create table if not exists genre (\n",
|
|
||||||
" id integer not null primary key autoincrement,\n",
|
|
||||||
" name varchar(64) not null\n",
|
|
||||||
" )\n",
|
|
||||||
"\"\"\"\n",
|
|
||||||
"\n",
|
|
||||||
"create_regie = \"\"\"\n",
|
|
||||||
" create table if not exists regie (\n",
|
|
||||||
" id integer not null primary key autoincrement,\n",
|
|
||||||
" surname varchar(64) not null,\n",
|
|
||||||
" lastname varchr(64) not null\n",
|
|
||||||
" )\n",
|
|
||||||
"\"\"\"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"with DBcm.UseDatabase(db_name) as db: \n",
|
|
||||||
" db.execute(create_my_list)\n",
|
|
||||||
" db.execute(create_genre)\n",
|
|
||||||
" db.execute(create_regie)\n",
|
|
||||||
" "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 3,
|
|
||||||
"id": "376ef812-97b5-45ba-8ef1-eb8d7829494a",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# ADDed Genre values\n",
|
|
||||||
"\n",
|
|
||||||
"ADD_GENRE_VALUE = \"\"\"\n",
|
|
||||||
" INSERT INTO genre(name)\n",
|
|
||||||
" SELECT ?\n",
|
|
||||||
" WHERE NOT EXISTS (SELECT 1 FROM genre WHERE name = ?);\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
"\n",
|
|
||||||
"with open(\"genre_list\", \"r\") as fs: \n",
|
|
||||||
" for genre_value in fs.readlines():\n",
|
|
||||||
" with DBcm.UseDatabase(db_name) as db:\n",
|
|
||||||
" db.execute(ADD_GENRE_VALUE, (genre_value.strip(), genre_value.strip()))\n",
|
|
||||||
" "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 27,
|
|
||||||
"id": "63b16a41-88bf-4832-a26c-09180832f597",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"['action', 'adventure', 'animation', 'biography', 'comedy', 'crime', 'cult movie', 'disney', 'documentary', 'drama', 'erotic', 'family', 'fantasy', 'film-noir', 'gangster', 'gay and lesbian', 'history', 'horror', 'military', 'music', 'musical', 'mystery', 'nature', 'neo-noir', 'period', 'pixar', 'road movie', 'romance', 'sci-fi', 'short', 'spy', 'super hero', 'thriller', 'visually stunning', 'war', 'western']\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"def all_genres():\n",
|
|
||||||
" ALL_GENRE = \"\"\"\n",
|
|
||||||
" SELECT * from genre \n",
|
|
||||||
" \"\"\" \n",
|
|
||||||
" with DBcm.UseDatabase(db_name) as db:\n",
|
|
||||||
" db.execute(ALL_GENRE)\n",
|
|
||||||
" all_genre = [i[1] for i in db.fetchall()]\n",
|
|
||||||
" \n",
|
|
||||||
" return all_genre\n",
|
|
||||||
"\n",
|
|
||||||
"print(all_genres())\n",
|
|
||||||
" "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 36,
|
|
||||||
"id": "89b20b5f-34aa-4490-a4c0-c186c9fa30bd",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"1\n",
|
|
||||||
"36\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"def search_genre_id(genre_name):\n",
|
|
||||||
" GENRE_QUERY = \"\"\"\n",
|
|
||||||
" select id from genre\n",
|
|
||||||
" where name = ?\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" try:\n",
|
|
||||||
" with DBcm.UseDatabase(db_name) as db:\n",
|
|
||||||
" db.execute(GENRE_QUERY,(genre_name,))\n",
|
|
||||||
" genre_id = db.fetchone()[0]\n",
|
|
||||||
" return int(genre_id)\n",
|
|
||||||
" except:\n",
|
|
||||||
" return int(0)\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def search_medium_id(genre_name):\n",
|
|
||||||
" GENRE_QUERY = \"\"\"\n",
|
|
||||||
" select id from genre\n",
|
|
||||||
" where medium = ?\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" try:\n",
|
|
||||||
" with DBcm.UseDatabase(db_name) as db:\n",
|
|
||||||
" db.execute(GENRE_QUERY,(genre_name,))\n",
|
|
||||||
" genre_id = db.fetchone()[0]\n",
|
|
||||||
" return int(genre_id)\n",
|
|
||||||
" except:\n",
|
|
||||||
" return int(0)\n",
|
|
||||||
"\n",
|
|
||||||
"print(search_genre_id(genre_name=\"action\"))\n",
|
|
||||||
"print(search_genre_id(genre_name=\"western\"))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 18,
|
|
||||||
"id": "c70d91a5-7855-465d-a4a6-daebc065ee37",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"0-John-Smith\n",
|
|
||||||
"1-James-Johnson\n",
|
|
||||||
"2-William-Williams\n",
|
|
||||||
"3-Michael-Brown\n",
|
|
||||||
"4-David-Davis\n",
|
|
||||||
"5-Richard-Miller\n",
|
|
||||||
"6-Joseph-Wilson\n",
|
|
||||||
"7-Charles-Moore\n",
|
|
||||||
"8-Thomas-Taylor\n",
|
|
||||||
"9-Daniel-Anderson\n",
|
|
||||||
"10-Paul-Thomas\n",
|
|
||||||
"11-Mark-Jackson\n",
|
|
||||||
"12-Donna-White\n",
|
|
||||||
"13-Michelle-Harris\n",
|
|
||||||
"14-Laura-Martin\n",
|
|
||||||
"15-Sara-Thompson\n",
|
|
||||||
"16-Ana-Garcia\n",
|
|
||||||
"17-Carlos-Rodriguez\n",
|
|
||||||
"18-Maria-Martinez\n",
|
|
||||||
"19-Jose-Hernandez\n",
|
|
||||||
"20-Luis-Lopez\n",
|
|
||||||
"21-Rosa-Gonzalez\n",
|
|
||||||
"22-Pedro-Perez\n",
|
|
||||||
"23-Miguel-Sanchez\n",
|
|
||||||
"24-Juan-Ramirez\n",
|
|
||||||
"25-Ana-Flores\n",
|
|
||||||
"26-Isabella-Cruz\n",
|
|
||||||
"27-Victor-Rivera\n",
|
|
||||||
"28-Kevin-Lee\n",
|
|
||||||
"29-Brian-Walker\n",
|
|
||||||
"30-Emily-Hall\n",
|
|
||||||
"31-Ryan-Allen\n",
|
|
||||||
"32-Aaron-Young\n",
|
|
||||||
"33-Jeffrey-King\n",
|
|
||||||
"34-Joshua-Wright\n",
|
|
||||||
"35-Brandon-Scott\n",
|
|
||||||
"36-Frank-Turner\n",
|
|
||||||
"37-Gregory-Carter\n",
|
|
||||||
"38-Samuel-Phillips\n",
|
|
||||||
"39-Chris-Evans\n",
|
|
||||||
"40-Anthony-Collins\n",
|
|
||||||
"41-Eric-Stewart\n",
|
|
||||||
"42-Frank-Snyder\n",
|
|
||||||
"43-Thomas-Baker\n",
|
|
||||||
"44-Jeremy-Nelson\n",
|
|
||||||
"45-Steven-Roberts\n",
|
|
||||||
"46-Edward-Campbell\n",
|
|
||||||
"47-Ryan-Miller\n",
|
|
||||||
"48-Jacob-Davis\n",
|
|
||||||
"49-David-Garcia\n",
|
|
||||||
"50-Sophia-Rodriguez\n",
|
|
||||||
"51-Emma-Martinez\n",
|
|
||||||
"52-Noah-Hernandez\n",
|
|
||||||
"53-Ava-Lopez\n",
|
|
||||||
"54-Ethan-Gonzalez\n",
|
|
||||||
"55-Mia-Perez\n",
|
|
||||||
"56-William-Sanchez\n",
|
|
||||||
"57-James-Ramirez\n",
|
|
||||||
"58-Olivia-Flores\n",
|
|
||||||
"59-Lucas-Cruz\n",
|
|
||||||
"60-Isabella-Rivera\n",
|
|
||||||
"61-David-Lee\n",
|
|
||||||
"62-Sophie-Walker\n",
|
|
||||||
"63-Matthew-Hall\n",
|
|
||||||
"64-Emma-Allen\n",
|
|
||||||
"65-Ryan-Young\n",
|
|
||||||
"66-Ava-King\n",
|
|
||||||
"67-Ethan-Wright\n",
|
|
||||||
"68-Mia-Scott\n",
|
|
||||||
"69-William-Turner\n",
|
|
||||||
"70-James-Carter\n",
|
|
||||||
"71-Olivia-Phillips\n",
|
|
||||||
"72-Lucas-Evans\n",
|
|
||||||
"73-Sophie-Collins\n",
|
|
||||||
"74-Noah-Stewart\n",
|
|
||||||
"75-Ava-Snyder\n",
|
|
||||||
"76-Ethan-Baker\n",
|
|
||||||
"77-Mia-Nelson\n",
|
|
||||||
"78-Noah-Roberts\n",
|
|
||||||
"79-Emma-Campbell\n",
|
|
||||||
"80-William-Miller\n",
|
|
||||||
"81-James-Davis\n",
|
|
||||||
"82-Olivia-Garcia\n",
|
|
||||||
"83-Lucas-Rodriguez\n",
|
|
||||||
"84-Sophie-Martinez\n",
|
|
||||||
"85-Noah-Hernandez\n",
|
|
||||||
"86-Ava-Lopez\n",
|
|
||||||
"87-Ethan-Gonzalez\n",
|
|
||||||
"88-Mia-Perez\n",
|
|
||||||
"89-William-Sanchez\n",
|
|
||||||
"90-James-Ramirez\n",
|
|
||||||
"91-Olivia-Flores\n",
|
|
||||||
"92-Lucas-Cruz\n",
|
|
||||||
"93-Isabella-Rivera\n",
|
|
||||||
"94-David-Lee\n",
|
|
||||||
"95-Sophie-Walker\n",
|
|
||||||
"96-Matthew-Hall\n",
|
|
||||||
"97-Emma-Allen\n",
|
|
||||||
"98-Ryan-Young\n",
|
|
||||||
"99-Ava-King\n",
|
|
||||||
"100-Ethan-Wright\n",
|
|
||||||
"101-Mia-Scott\n",
|
|
||||||
"102-William-Turner\n",
|
|
||||||
"103-James-Carter\n",
|
|
||||||
"104-Olivia-Phillips\n",
|
|
||||||
"105-Lucas-Evans\n",
|
|
||||||
"106-Sophie-Collins\n",
|
|
||||||
"107-Noah-Stewart\n",
|
|
||||||
"108-Ava-Snyder\n",
|
|
||||||
"109-Ethan-Baker\n",
|
|
||||||
"110-Mia-Nelson\n",
|
|
||||||
"111-Noah-Roberts\n",
|
|
||||||
"112-Emma-Campbell\n",
|
|
||||||
"113-William-Miller\n",
|
|
||||||
"114-James-Davis\n",
|
|
||||||
"115-Olivia-Garcia\n",
|
|
||||||
"116-Lucas-Rodriguez\n",
|
|
||||||
"117-Sophie-Martinez\n",
|
|
||||||
"118-Noah-Hernandez\n",
|
|
||||||
"119-Ava-Lopez\n",
|
|
||||||
"120-Ethan-Gonzalez\n",
|
|
||||||
"121-Mia-Perez\n",
|
|
||||||
"122-William-Sanchez\n",
|
|
||||||
"123-James-Ramirez\n",
|
|
||||||
"124-Olivia-Flores\n",
|
|
||||||
"125-Lucas-Cruz\n",
|
|
||||||
"126-Isabella-Rivera\n",
|
|
||||||
"127-David-Lee\n",
|
|
||||||
"128-Sophie-Walker\n",
|
|
||||||
"129-Matthew-Hall\n",
|
|
||||||
"130-Emma-Allen\n",
|
|
||||||
"131-Ryan-Young\n",
|
|
||||||
"132-Ava-King\n",
|
|
||||||
"133-Ethan-Wright\n",
|
|
||||||
"134-Mia-Scott\n",
|
|
||||||
"135-William-Turner\n",
|
|
||||||
"136-James-Carter\n",
|
|
||||||
"137-Olivia-Phillips\n",
|
|
||||||
"138-Lucas-Evans\n",
|
|
||||||
"139-Sophie-Collins\n",
|
|
||||||
"140-Noah-Stewart\n",
|
|
||||||
"141-Ava-Snyder\n",
|
|
||||||
"142-Ethan-Baker\n",
|
|
||||||
"143-Mia-Nelson\n",
|
|
||||||
"144-Noah-Roberts\n",
|
|
||||||
"145-Emma-Campbell\n",
|
|
||||||
"146-William-Miller\n",
|
|
||||||
"147-James-Davis\n",
|
|
||||||
"148-Olivia-Garcia\n",
|
|
||||||
"149-Lucas-Rodriguez\n",
|
|
||||||
"150-Sophie-Martinez\n",
|
|
||||||
"151-Noah-Hernandez\n",
|
|
||||||
"152-Ava-Lopez\n",
|
|
||||||
"153-Ethan-Gonzalez\n",
|
|
||||||
"154-Mia-Perez\n",
|
|
||||||
"155-William-Sanchez\n",
|
|
||||||
"156-James-Ramirez\n",
|
|
||||||
"157-Olivia-Flores\n",
|
|
||||||
"158-Lucas-Cruz\n",
|
|
||||||
"159-Isabella-Rivera\n",
|
|
||||||
"160-David-Lee\n",
|
|
||||||
"161-Sophie-Walker\n",
|
|
||||||
"162-Matthew-Hall\n",
|
|
||||||
"163-Emma-Allen\n",
|
|
||||||
"164-Ryan-Young\n",
|
|
||||||
"165-Ava-King\n",
|
|
||||||
"166-Ethan-Wright\n",
|
|
||||||
"167-Mia-Scott\n",
|
|
||||||
"168-William-Turner\n",
|
|
||||||
"169-James-Carter\n",
|
|
||||||
"170-Olivia-Phillips\n",
|
|
||||||
"171-Lucas-Evans\n",
|
|
||||||
"172-Sophie-Collins\n",
|
|
||||||
"173-Noah-Stewart\n",
|
|
||||||
"174-Ava-Snyder\n",
|
|
||||||
"175-Ethan-Baker\n",
|
|
||||||
"176-Mia-Nelson\n",
|
|
||||||
"177-Noah-Roberts\n",
|
|
||||||
"178-Emma-Campbell\n",
|
|
||||||
"179-William-Miller\n",
|
|
||||||
"180-James-Davis\n",
|
|
||||||
"181-Olivia-Garcia\n",
|
|
||||||
"182-Lucas-Rodriguez\n",
|
|
||||||
"183-Sophie-Martinez\n",
|
|
||||||
"184-Noah-Hernandez\n",
|
|
||||||
"185-Ava-Lopez\n",
|
|
||||||
"186-Ethan-Gonzalez\n",
|
|
||||||
"187-Mia-Perez\n",
|
|
||||||
"188-William-Sanchez\n",
|
|
||||||
"189-James-Ramirez\n",
|
|
||||||
"190-Olivia-Flores\n",
|
|
||||||
"191-Lucas-Cruz\n",
|
|
||||||
"192-Isabella-Rivera\n",
|
|
||||||
"193-David-Lee\n",
|
|
||||||
"194-Sophie-Walker\n",
|
|
||||||
"195-Matthew-Hall\n",
|
|
||||||
"196-Emma-Allen\n",
|
|
||||||
"197-Ryan-Young\n",
|
|
||||||
"198-Ava-King\n",
|
|
||||||
"199-Ethan-Wright\n",
|
|
||||||
"200-Mia-Scott\n",
|
|
||||||
"201-William-Turner\n",
|
|
||||||
"202-James-Carter\n",
|
|
||||||
"203-Olivia-Phillips\n",
|
|
||||||
"204-Lucas-Evans\n",
|
|
||||||
"205-Sophie-Collins\n",
|
|
||||||
"206-Noah-Stewart\n",
|
|
||||||
"207-Ava-Snyder\n",
|
|
||||||
"208-Ethan-Baker\n",
|
|
||||||
"209-Mia-Nelson\n",
|
|
||||||
"210-Noah-Roberts\n",
|
|
||||||
"211-Emma-Campbell\n",
|
|
||||||
"212-William-Miller\n",
|
|
||||||
"213-James-Davis\n",
|
|
||||||
"214-Olivia-Garcia\n",
|
|
||||||
"215-Lucas-Rodriguez\n",
|
|
||||||
"216-Sophie-Martinez\n",
|
|
||||||
"217-Noah-Hernandez\n",
|
|
||||||
"218-Ava-Lopez\n",
|
|
||||||
"219-Ethan-Gonzalez\n",
|
|
||||||
"220-Mia-Perez\n",
|
|
||||||
"221-William-Sanchez\n",
|
|
||||||
"222-James-Ramirez\n",
|
|
||||||
"223-Olivia-Flores\n",
|
|
||||||
"224-Lucas-Cruz\n",
|
|
||||||
"225-Isabella-Rivera\n",
|
|
||||||
"226-David-Lee\n",
|
|
||||||
"227-Sophie-Walker\n",
|
|
||||||
"228-Matthew-Hall\n",
|
|
||||||
"229-Emma-Allen\n",
|
|
||||||
"230-Ryan-Young\n",
|
|
||||||
"231-Ava-King\n",
|
|
||||||
"232-Ethan-Wright\n",
|
|
||||||
"233-Mia-Scott\n",
|
|
||||||
"234-William-Turner\n",
|
|
||||||
"235-James-Carter\n",
|
|
||||||
"236-Olivia-Phillips\n",
|
|
||||||
"237-Lucas-Evans\n",
|
|
||||||
"238-Sophie-Collins\n",
|
|
||||||
"239-Noah-Stewart\n",
|
|
||||||
"240-Ava-Snyder\n",
|
|
||||||
"241-Ethan-Baker\n",
|
|
||||||
"242-Mia-Nelson\n",
|
|
||||||
"243-Noah-Roberts\n",
|
|
||||||
"244-Emma-Campbell\n",
|
|
||||||
"245-William-Miller\n",
|
|
||||||
"246-James-Davis\n",
|
|
||||||
"247-Olivia-Garcia\n",
|
|
||||||
"248-Lucas-Rodriguez\n",
|
|
||||||
"249-Sophie-Martinez\n",
|
|
||||||
"250-Noah-Hernandez\n",
|
|
||||||
"251-Ava-Lopez\n",
|
|
||||||
"252-Ethan-Gonzalez\n",
|
|
||||||
"253-Mia-Perez\n",
|
|
||||||
"254-William-Sanchez\n",
|
|
||||||
"255-James-Ramirez\n",
|
|
||||||
"256-Olivia-Flores\n",
|
|
||||||
"257-Lucas-Cruz\n",
|
|
||||||
"258-Isabella-Rivera\n",
|
|
||||||
"259-David-Lee\n",
|
|
||||||
"260-Sophie-Walker\n",
|
|
||||||
"261-Matthew-Hall\n",
|
|
||||||
"262-Emma-Allen\n",
|
|
||||||
"263-Ryan-Young\n",
|
|
||||||
"264-Ava-King\n",
|
|
||||||
"265-Ethan-Wright\n",
|
|
||||||
"266-Mia-Scott\n",
|
|
||||||
"267-William-Turner\n",
|
|
||||||
"268-James-Carter\n",
|
|
||||||
"269-Olivia-Phillips\n",
|
|
||||||
"270-Lucas-Evans\n",
|
|
||||||
"271-Sophie-Collins\n",
|
|
||||||
"272-Noah-Stewart\n",
|
|
||||||
"273-Ava-Snyder\n",
|
|
||||||
"274-Ethan-Baker\n",
|
|
||||||
"275-Mia-Nelson\n",
|
|
||||||
"276-Noah-Roberts\n",
|
|
||||||
"277-Emma-Campbell\n",
|
|
||||||
"278-William-Miller\n",
|
|
||||||
"279-James-Davis\n",
|
|
||||||
"280-Olivia-Garcia\n",
|
|
||||||
"281-Lucas-Rodriguez\n",
|
|
||||||
"282-Sophie-Martinez\n",
|
|
||||||
"283-Noah-Hernandez\n",
|
|
||||||
"284-Ava-Lopez\n",
|
|
||||||
"285-Ethan-Gonzalez\n",
|
|
||||||
"286-Mia-Perez\n",
|
|
||||||
"287-William-Sanchez\n",
|
|
||||||
"288-James-Ramirez\n",
|
|
||||||
"289-Olivia-Flores\n",
|
|
||||||
"290-Lucas-Cruz\n",
|
|
||||||
"291-Isabella-Rivera\n",
|
|
||||||
"292-David-Lee\n",
|
|
||||||
"293-Sophie-Walker\n",
|
|
||||||
"294-Matthew-Hall\n",
|
|
||||||
"295-Emma-Allen\n",
|
|
||||||
"296-Ryan-Young\n",
|
|
||||||
"297-Ava-King\n",
|
|
||||||
"298-Ethan-Wright\n",
|
|
||||||
"299-Mia-Scott\n",
|
|
||||||
"300-William-Turner\n",
|
|
||||||
"301-James-Carter\n",
|
|
||||||
"302-Olivia-Phillips\n",
|
|
||||||
"303-Lucas-Evans\n",
|
|
||||||
"304-Sophie-Collins\n",
|
|
||||||
"305-Noah-Stewart\n",
|
|
||||||
"306-Ava-Snyder\n",
|
|
||||||
"307-Ethan-Baker\n",
|
|
||||||
"308-Mia-Nelson\n",
|
|
||||||
"309-Noah-Roberts\n",
|
|
||||||
"310-Emma-Campbell\n",
|
|
||||||
"311-William-Miller\n",
|
|
||||||
"312-James-Davis\n",
|
|
||||||
"313-Olivia-Garcia\n",
|
|
||||||
"314-Lucas-Rodriguez\n",
|
|
||||||
"315-Sophie-Martinez\n",
|
|
||||||
"316-Noah-Hernandez\n",
|
|
||||||
"317-Ava-Lopez\n",
|
|
||||||
"318-Ethan-Gonzalez\n",
|
|
||||||
"319-Mia-Perez\n",
|
|
||||||
"320-William-Sanchez\n",
|
|
||||||
"321-James-Ramirez\n",
|
|
||||||
"322-Olivia-Flores\n",
|
|
||||||
"323-Lucas-Cruz\n",
|
|
||||||
"324-Isabella-Rivera\n",
|
|
||||||
"325-David-Lee\n",
|
|
||||||
"326-Sophie-Walker\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"import pandas as pd\n",
|
|
||||||
"usecols = [\"Name\", \"Vorname\"]\n",
|
|
||||||
"air = pd.read_csv(\"regie_name.csv\", usecols=usecols)\n",
|
|
||||||
"\n",
|
|
||||||
"for count, (i, b) in enumerate(zip(air[\"Name\"], air[\"Vorname\"])):\n",
|
|
||||||
" print(count, b, i, sep=\"-\")\n",
|
|
||||||
"\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"id": "ee4b5dee-6b41-49eb-8d75-9db50d20fdef",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3 (ipykernel)",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.13.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 5
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
FROM python:3.9-slim-bookworm
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install build dependencies for mariadb-connector-c
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
default-libmysqlclient-dev \
|
||||||
|
gcc \
|
||||||
|
pkg-config \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 5082
|
||||||
|
|
||||||
|
CMD ["python3", "main.py"]
|
||||||
+116
-5
@@ -1,7 +1,118 @@
|
|||||||
Folgende Punkte
|
# Movie-DB
|
||||||
|
|
||||||
- erstellen eine SQlite DB
|
Eine webbasierte Anwendung zur Verwaltung einer persönlichen Filmsammlung.
|
||||||
- Die DB soll folgende Tabellen haben Genre, MyList,
|
|
||||||
- Die Anzeige soll über Flask angezeigt werden
|
|
||||||
|
|
||||||
Weitere Schritte folgen !!!
|
## Funktionsumfang (Features)
|
||||||
|
|
||||||
|
* **Benutzer-System:** Vollständiges Registrierungs- und Login-System, sodass jeder Benutzer seine eigene, private Filmsammlung verwalten kann.
|
||||||
|
* **Persönliche Filmlisten:** Jeder Benutzer sieht und durchsucht nur die Filme, die er selbst hinzugefügt hat.
|
||||||
|
* **Filme hinzufügen:** Filme können manuell oder durch ein automatisiertes Scraping von IMDb hinzugefügt werden.
|
||||||
|
* **Umfassende Suche:** Eine globale Suchleiste ermöglicht die gleichzeitige Suche nach Titel, Genre und Regisseur.
|
||||||
|
* **Paginierung:** Die Filmliste ist in Seiten aufgeteilt, um auch bei großen Sammlungen übersichtlich zu bleiben.
|
||||||
|
* **Sichere Verbindung:** Die Anwendung wird über HTTPS mit einem selbst-signierten SSL-Zertifikat bereitgestellt.
|
||||||
|
* **Containerisierung:** Die gesamte Anwendung ist mit Docker und Docker Compose containerisiert, was die Bereitstellung vereinfacht.
|
||||||
|
* **Automatisierte Bereitstellung:** Ein Ansible-Playbook automatisiert das Deployment der Anwendung.
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
Stellen Sie sicher, dass die folgende Software auf Ihrem System installiert ist:
|
||||||
|
|
||||||
|
* Python 3
|
||||||
|
* pip
|
||||||
|
* Docker
|
||||||
|
* Docker Compose
|
||||||
|
* Ansible
|
||||||
|
|
||||||
|
## Inbetriebnahme
|
||||||
|
|
||||||
|
Es gibt drei Möglichkeiten, die Anwendung zu starten.
|
||||||
|
|
||||||
|
### 1. Direkter Start mit Python
|
||||||
|
|
||||||
|
Dies ist die klassische Methode für die lokale Entwicklung.
|
||||||
|
|
||||||
|
1. **Abhängigkeiten installieren:**
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
2. **Anwendung starten:**
|
||||||
|
```bash
|
||||||
|
python3 main.py
|
||||||
|
```
|
||||||
|
3. **Zugriff:** Öffnen Sie Ihren Browser und gehen Sie zu `https://localhost:5082`. Sie müssen eine Browser-Warnung aufgrund des selbst-signierten Zertifikats akzeptieren.
|
||||||
|
|
||||||
|
### 2. Start mit Docker
|
||||||
|
|
||||||
|
Diese Methode kapselt die Anwendung in einem Container.
|
||||||
|
|
||||||
|
1. **Docker-Image erstellen:**
|
||||||
|
```bash
|
||||||
|
docker build -t movie-db-app .
|
||||||
|
```
|
||||||
|
2. **Docker-Container starten:**
|
||||||
|
```bash
|
||||||
|
docker run -p 5082:5082 movie-db-app
|
||||||
|
```
|
||||||
|
3. **Zugriff:** Öffnen Sie Ihren Browser und gehen Sie zu `https://localhost:5082`.
|
||||||
|
|
||||||
|
### 3. Start mit Ansible und Docker Compose (Empfohlen)
|
||||||
|
|
||||||
|
Dies ist die automatisierte Methode, die einen sauberen Deployment-Prozess sicherstellt.
|
||||||
|
|
||||||
|
1. **Ansible Docker-Sammlung installieren (falls noch nicht geschehen):**
|
||||||
|
```bash
|
||||||
|
ansible-galaxy collection install community.docker
|
||||||
|
```
|
||||||
|
2. **Ansible-Playbook ausführen:**
|
||||||
|
```bash
|
||||||
|
ansible-playbook start.yml
|
||||||
|
```
|
||||||
|
(Möglicherweise müssen Sie Ihr `sudo`-Passwort eingeben.)
|
||||||
|
|
||||||
|
3. **Zugriff:** Öffnen Sie Ihren Browser und gehen Sie zu `https://localhost:5082`.
|
||||||
|
|
||||||
|
## Projektstruktur
|
||||||
|
|
||||||
|
Die wichtigsten Dateien und Ordner im Überblick:
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── Dockerfile
|
||||||
|
├── docker-compose.yml
|
||||||
|
├── main.py
|
||||||
|
├── moviedb_func.py
|
||||||
|
├── movie_db.db
|
||||||
|
├── README.md
|
||||||
|
├── requirements.txt
|
||||||
|
├── start.yml
|
||||||
|
├── cert.pem
|
||||||
|
├── key.pem
|
||||||
|
└── templates/
|
||||||
|
├── base.html
|
||||||
|
├── index.html
|
||||||
|
├── login.html
|
||||||
|
└── register.html
|
||||||
|
```
|
||||||
|
|
||||||
|
* `main.py`: Die Hauptdatei der Flask-Anwendung. Sie enthält die Routen und die Anwendungslogik.
|
||||||
|
* `moviedb_func.py`: Enthält die gesamte Geschäftslogik, Datenbankfunktionen und die `User`-Klasse.
|
||||||
|
* `templates/`: Der Ordner für alle HTML-Templates.
|
||||||
|
* `movie_db.db`: Die SQLite-Datenbankdatei.
|
||||||
|
* `Dockerfile`: Die Bauanleitung für das Docker-Image der Anwendung.
|
||||||
|
* `docker-compose.yml`: Definiert die Anwendung als Docker-Dienst für eine einfache Verwaltung.
|
||||||
|
* `start.yml`: Das Ansible-Playbook für die automatisierte Bereitstellung.
|
||||||
|
* `requirements.txt`: Liste der Python-Abhängigkeiten.
|
||||||
|
* `cert.pem`, `key.pem`: Das selbst-signierte SSL-Zertifikat und der private Schlüssel.
|
||||||
|
|
||||||
|
## Benutzung
|
||||||
|
|
||||||
|
1. **Registrieren:** Erstellen Sie auf der Registrierungsseite einen neuen Benutzeraccount.
|
||||||
|
2. **Einloggen:** Melden Sie sich mit Ihren neuen Zugangsdaten an.
|
||||||
|
3. **Filme hinzufügen:** Nutzen Sie den "Film hinzufügen"-Button, um Filme entweder durch die IMDb-Suche oder manuell zu Ihrer Sammlung hinzuzufügen.
|
||||||
|
4. **Suchen:** Verwenden Sie die Suchleiste, um Ihre Sammlung nach Titeln, Genres oder Regisseuren zu durchsuchen.
|
||||||
|
|
||||||
|
## Mögliche zukünftige Erweiterungen
|
||||||
|
|
||||||
|
* **Bearbeiten & Löschen:** Funktionen zum Bearbeiten und Löschen von bereits hinzugefügten Filmen.
|
||||||
|
* **Detailseite:** Eine eigene Seite für jeden Film mit mehr Details (Schauspieler, Handlung, etc.).
|
||||||
|
* **Sortieroptionen:** Die Möglichkeit, die Filmliste nach verschiedenen Kriterien zu sortieren.
|
||||||
Binary file not shown.
@@ -0,0 +1,29 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFCTCCAvGgAwIBAgIUDplU7xn71S8Rb5v7dXQ9cZmD1S4wDQYJKoZIhvcNAQEL
|
||||||
|
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MDgyNjExNTIwMVoXDTI2MDgy
|
||||||
|
NjExNTIwMVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
|
||||||
|
AAOCAg8AMIICCgKCAgEA0J1PNqsrg+BL/zy7nTaRwfP96gGGvnQtHFHBifX7qF6e
|
||||||
|
bXKvxU77tGE9D0i5t36N2ktMl6PGI2CmhFz5mkcVrXnfWGLoYV2jLlYQOdKvwFJo
|
||||||
|
7R4QuGa8nLHLdGUkhSSgRxkol9rHUcok5ZpfA1iVFbrpgqel3Lmh0h3qXx7YiPTo
|
||||||
|
Y8ZhFQDoF4TXJYGrSC2BlAtbOSwT/L/n983VIA3dugzQ+3H78OWmfGcCB8Q8d5hN
|
||||||
|
FP+igWj/29U3vCmvlgXpzaM+X1TtL9uxqm/GWw/+jIj4Wn+2mxhMFS2B/OeWEW5y
|
||||||
|
oTYvZywK/eap9ieyKpzi+lND3eTvD+icpj1hFBt5qa+R9P1bj369q6IMSxNrf5YJ
|
||||||
|
cDesywy5MIIAPN+21nNYi13ZSwSnfEI/13klBk0rdhBulDAPGvH1DZEAc4ePagMQ
|
||||||
|
uhJtW6wl50yNJADxszAa1mbIIk/v7r+vPt32XTylqlaI3koU2XjjmyXcsAFLdgcS
|
||||||
|
ymCtxNWe37U58qb1J3QKDbaskq6kJiJBWZlASa3ANp19UdWvAnuznhhfXws0cV6b
|
||||||
|
qFoeKKkyWOsPln+Ifuw1VONJOMJmoT4L+kHuKnMDqdusuGdIlJXfeW00vMLIRx8O
|
||||||
|
8j8dUHfFqWRnE98VO9WZlsbagYgW96n9zyeZvfW3VgncrqMVZYC2YadbSH+hG40C
|
||||||
|
AwEAAaNTMFEwHQYDVR0OBBYEFIp7yQD9oKNeYS2hFMBzgIQWoZzGMB8GA1UdIwQY
|
||||||
|
MBaAFIp7yQD9oKNeYS2hFMBzgIQWoZzGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
|
||||||
|
hvcNAQELBQADggIBAHQpvGXNoeHjmVxuMmZSuiccOdfJXiWBTM7g7Eqq0nzTuzK/
|
||||||
|
IvmBkTxK8BG1j9X+9vBDJ3KZAIMVviepqxUNMGMQNa9DcVnOxaB01UdRqM9hh+jg
|
||||||
|
EkBgN325BgrX5Vh/HS7MX2VboM+WmBcfWtt3afKv2Tv2mzZ6bPPDdbH/SJouxfXD
|
||||||
|
Ea+n3IXniskmY7kUVTy7uRQUAJXyLulcrXAJgOwws80JEXrrjZwcpt9PxzzxXu4c
|
||||||
|
TUZQ1A5FgHgXecYM1WJA9nQr7NH9TewssKaoYOEltwOxbqc0bxAOtFX02dSTpRY/
|
||||||
|
0LwLC1Nqm34c96CX1t/WLfWf/RY2j5FoqFKxOY6CnpCW4DXjMZ3OEPmikT6XJ85G
|
||||||
|
q9LB4AqT/G1cyQzoT78SwDk6Ln3ahzP0MiaQeZ/KBJbqnfxOtcDWAmRTtIPYpMYH
|
||||||
|
eW8K+Y0Z3UvR+FqawuR5pvz5T/XYC/tutK4+KLCecorruT/Ye5qEALb+XcugU5iE
|
||||||
|
3FeZ/iAUxn8UKAGtfogQHYMOZ5lllAgRCKYhEYp28Rlkrk9LBXPzMimUfPZ2RSwx
|
||||||
|
XSkTYZEFEMw+4YQdOGqesW/hGpG6Ojmb/bmqG5TAzTdFUXsc6YgrJIP7lCIkEBnb
|
||||||
|
jF+S8Yb9Gq1s3ohiyI71kdVoOgWUGbqkkQ9xEZQzRzB1zcOLKelpdI7BEkjE
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
services:
|
||||||
|
web:
|
||||||
|
build: .
|
||||||
|
container_name: movie-db-web
|
||||||
|
ports:
|
||||||
|
- "5082:5082"
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
restart: always
|
||||||
|
# command: python3 main.py # Use this if you want to run in foreground for debugging
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Benötigt die Installation von 'requests' und 'beautifulsoup4'
|
||||||
|
# pip install requests beautifulsoup4
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
def suche_film_url(film_titel):
|
||||||
|
"""
|
||||||
|
Sucht auf IMDb nach einem Film und gibt die deutsche URL der Filmseite zurück.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
film_titel: Der Titel des Films, nach dem gesucht werden soll.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Die deutsche URL der Filmseite oder None, wenn nichts gefunden wurde.
|
||||||
|
"""
|
||||||
|
such_url = f"https://www.imdb.com/find?q={film_titel.replace(' ', '+')}"
|
||||||
|
# Header, um die deutsche Seite zu bevorzugen
|
||||||
|
headers = {
|
||||||
|
'Accept-Language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7',
|
||||||
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(such_url, headers=headers)
|
||||||
|
response.raise_for_status() # Löst eine Ausnahme für HTTP-Fehler aus
|
||||||
|
|
||||||
|
soup = BeautifulSoup(response.text, 'html.parser')
|
||||||
|
|
||||||
|
# Finden des ersten Links im Titel-Ergebnisbereich
|
||||||
|
ergebnis_bereich = soup.find('section', {'data-testid': 'find-results-section-title'})
|
||||||
|
if ergebnis_bereich:
|
||||||
|
link_tag = ergebnis_bereich.find('a', href=re.compile(r'/title/tt\d+'))
|
||||||
|
if link_tag and 'href' in link_tag.attrs:
|
||||||
|
pfad = link_tag['href']
|
||||||
|
# Extrahieren der Titel-ID (z.B. tt0133093)
|
||||||
|
match = re.search(r'(tt\d+)', pfad)
|
||||||
|
if match:
|
||||||
|
titel_id = match.group(1)
|
||||||
|
return f"https://www.imdb.com/de/title/{titel_id}"
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f"Ein Fehler bei der Anfrage ist aufgetreten: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
film_name = " ".join(sys.argv[1:])
|
||||||
|
url = suche_film_url(film_name)
|
||||||
|
if url:
|
||||||
|
print(f"URL für '{film_name}' gefunden: {url}")
|
||||||
|
else:
|
||||||
|
print(f"Konnte keinen Film mit dem Titel '{film_name}' finden.")
|
||||||
|
else:
|
||||||
|
print("Benutzung: python imdb_suche.py <film_titel>")
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDQnU82qyuD4Ev/
|
||||||
|
PLudNpHB8/3qAYa+dC0cUcGJ9fuoXp5tcq/FTvu0YT0PSLm3fo3aS0yXo8YjYKaE
|
||||||
|
XPmaRxWted9YYuhhXaMuVhA50q/AUmjtHhC4Zrycsct0ZSSFJKBHGSiX2sdRyiTl
|
||||||
|
ml8DWJUVuumCp6XcuaHSHepfHtiI9OhjxmEVAOgXhNclgatILYGUC1s5LBP8v+f3
|
||||||
|
zdUgDd26DND7cfvw5aZ8ZwIHxDx3mE0U/6KBaP/b1Te8Ka+WBenNoz5fVO0v27Gq
|
||||||
|
b8ZbD/6MiPhaf7abGEwVLYH855YRbnKhNi9nLAr95qn2J7IqnOL6U0Pd5O8P6Jym
|
||||||
|
PWEUG3mpr5H0/VuPfr2rogxLE2t/lglwN6zLDLkwggA837bWc1iLXdlLBKd8Qj/X
|
||||||
|
eSUGTSt2EG6UMA8a8fUNkQBzh49qAxC6Em1brCXnTI0kAPGzMBrWZsgiT+/uv68+
|
||||||
|
3fZdPKWqVojeShTZeOObJdywAUt2BxLKYK3E1Z7ftTnypvUndAoNtqySrqQmIkFZ
|
||||||
|
mUBJrcA2nX1R1a8Ce7OeGF9fCzRxXpuoWh4oqTJY6w+Wf4h+7DVU40k4wmahPgv6
|
||||||
|
Qe4qcwOp26y4Z0iUld95bTS8wshHHw7yPx1Qd8WpZGcT3xU71ZmWxtqBiBb3qf3P
|
||||||
|
J5m99bdWCdyuoxVlgLZhp1tIf6EbjQIDAQABAoICAD8OHWBX0ppU1IO8drTpRptK
|
||||||
|
RYhSl8i/UtdJeudZW4yjtN0+GhTYb8owzgTtpXzqGrRNqEP5c61DzHEbrTJNpCbA
|
||||||
|
PJr5omWzqNwblWH05byK7D4npUQngYEXWHjBDY3U6UE0QInNzgtRv19LDsbzInTj
|
||||||
|
/yrHw6F41omtEydXKnoTFJ772mI/2Ocq9uDWVdBGOPFnkVYxlYUC+Hl1VKMQreFL
|
||||||
|
eGtYI5/Huk/Fzt5MGT7I4RukvRjChPuMcgFE1FbTSL0oR3UHNX4OuJ/ckyb5KaaO
|
||||||
|
zAqGqcotSOnpzG2GDl0Mdkd2GlPkAxqFev/1NawdqZmiS1Qpm3zCgX7Z9JrgRyBP
|
||||||
|
nMKMdH/+Yi6sQ16BLuq1/wBSoN4hh5AIjbS2SRV8P0RR9TfuKP0G3UZeXEJVu7VZ
|
||||||
|
LjMqfNc5Frco8iJdm4dv9bAjMgDgKBwRzECTSPcUByS7H72v7I81X9HDaNlMk9Py
|
||||||
|
B0sy5mduihQE4ZeSUVloiq/Mm8K3/6lPuC94+8hfZ7ZhmMTsXkeHtyo+tNNEHtFS
|
||||||
|
wnF96zzUE5l7quCmqPzz5l5ll9wYAjMXr48Fv9C5E5QshoYhmzBrF6+Kn315bSa6
|
||||||
|
PHf3v2nJ//lJHyJR6o/MWLAdW61nbvnlLbwBUt0blv+PUnoOFKQhDcHteU7Ht5zi
|
||||||
|
vyzJKEGK0nL+hScit94dAoIBAQD+ttlWLHVo32jX83cVLNQFo5TVQJlbf05yZUqm
|
||||||
|
rEVu+kH59JAUPYxypiQ+CWc3OMFqDHiSrP9VdL1HSfZURS3K8hw25ThWn5jXEoWF
|
||||||
|
SkyCWBcPp8EyCwW14DUCp45VKyZlNpM/halT+eG04lElEilUHDMbinz01R2Gwkrk
|
||||||
|
zgirxRBpAU1OMnvCTTjwmLUXCKvHBDek4AZBY0Gw9eWgir+If6Gyn88Nr2N1ZtFt
|
||||||
|
+kkHrLgyo+nanOu1N/02RC3Je3lSxI7VsLP0Lt/zs5Qag8r/a7lEDUI69eQbh/Rh
|
||||||
|
29NaqUyPOQn8DjfPzB8a0F7qXbcB94CYWfoKZ/RkdJ9dj4mTAoIBAQDRquN/ftwE
|
||||||
|
CBfgwE5BJNZuofj733LBrnvZH51UOMvnoTxPDdCyf684un8qylmYu4WIV5VvWZUH
|
||||||
|
G3gOw+zmmpEOHerh8/G7X9FPST8txTlAxlFBVN0iXMyU8SDypw2XF+CKcq0goz2s
|
||||||
|
/XA0b9NdtF9zziYsZSj+hR5E1Nf16GX2SeczSlaxPRTZ1pxqRbmC+1iE+yJuXcQ2
|
||||||
|
sJgr2zI9jUf0zGamYPqpKvZDKLclZSJAIYTLE/nUMR87QqgLU90x3bBeRR4uLnD3
|
||||||
|
yemtFuJDRcSZa+4j/m5fmLZvA2wpvZvvd70DC3xfh6RKZYyzj26rHgK3qnY9owzS
|
||||||
|
q44qLTbNH3pfAoIBAQCHmjy2XdDb1iRw41LAWS8/GUlBBrUeOvY+fKJzfT8xx9Wc
|
||||||
|
BpE11VaSKtUcmdDzWynNFXqTS7pbelzSORQE5Rdt9dsDdqC5rRmnVlrzDQ0ST2dn
|
||||||
|
lD2MMMYHf6d5FE74FJLKS3W02am95Ug+DkZ43+RUvPaQcPf5OAQSHBnXGcEQAUet
|
||||||
|
P14yhTnRxV7M599wtdMNjrc49XMfGIJ+fUqUX4l8V8Zz3BRVCsx+UhCo5hg/F7qw
|
||||||
|
awcytVvfDEGnxEBEBZIfeDk6lmoXU2UyzqXIP+WweV8WVaCu1v1rksON3YP1vi/e
|
||||||
|
B9XC9KbN37OniMsfJmkpiORTN4OgSpuXZ2b4XlQ1AoIBAQCsVFMMdc6MmcJWfnlT
|
||||||
|
Xd3JrOOi0fPWcX1l5nA/yzb9OS8Cow5HyF7St6bSGuMtf+OvPp2amfy9jLxPFoZe
|
||||||
|
u+hBvCFUelbTdVvqWP/OtO3r6ZTbp87h8XhNaytzhg7Lg1qRMNRPoRyOVPimgMsv
|
||||||
|
l5Nk8am6j6L0H6HTXUXr3on/tpqLM6yxnMzIh3akeo6Rs9j75BZWtEcT1G4ejdlr
|
||||||
|
cfYUpPQyCD++T4t9g7eUyt0t7N7is5aB66YJ5S2Nse56kAXoVdMKji1X3ONt2wM5
|
||||||
|
29xNZcKkXvmFJVW9RQjf/fJvDvGR0Rz2v9wvMexFobyKdO4y26631o4xkcQVsnf6
|
||||||
|
fMbtAoIBAE6rOneLYxM8X6hJ7NoyVIwUH52WKuqWn4SFHU42C8SGeUTxFtr6ze+L
|
||||||
|
z0ZYTowYufMOUMjtS4nwa2kWkohPJccDfJHG1NJf6WA80Yt/qQItsjv/TGItxDE0
|
||||||
|
4j47r+h1NGj01xzJHe0QG38NWnnpw0hHFSG5q73qWFyYSWs/unz+HMSGsg+KtpPT
|
||||||
|
K7RJMx2ROUXlMku8TmEWO0EfwhVmTp2g/1XoH7DvtAIv5GLiUL+pYp9qs7LtSVI/
|
||||||
|
3WYsk3Op/x5VRG/V2hByPf25IrpLS3eoDB3uPeeIHb0rXx0QdMr2rElGg4vgcLUw
|
||||||
|
krvHLxyb9R+o1UzlvYkUiF+lOMVpLB8=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
+96
-28
@@ -1,59 +1,127 @@
|
|||||||
import flask
|
import flask
|
||||||
|
from flask import render_template, redirect, url_for, flash
|
||||||
|
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
|
||||||
|
|
||||||
import moviedb_func
|
import moviedb_func
|
||||||
|
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
app.secret_key = "Start1234!"
|
app.secret_key = "Start1234!"
|
||||||
|
|
||||||
|
login_manager = LoginManager()
|
||||||
|
login_manager.init_app(app)
|
||||||
|
login_manager.login_view = "login"
|
||||||
|
|
||||||
|
@login_manager.user_loader
|
||||||
|
def load_user(user_id):
|
||||||
|
return moviedb_func.get_user_by_id(user_id)
|
||||||
|
|
||||||
|
@app.route("/register", methods=["GET", "POST"])
|
||||||
|
def register():
|
||||||
|
if flask.request.method == "POST":
|
||||||
|
username = flask.request.form.get("username")
|
||||||
|
password = flask.request.form.get("password")
|
||||||
|
if moviedb_func.get_user_by_username(username):
|
||||||
|
flash("Benutzername existiert bereits")
|
||||||
|
return redirect(url_for("register"))
|
||||||
|
moviedb_func.add_user(username, password)
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
return render_template("register.html")
|
||||||
|
|
||||||
|
@app.route("/login", methods=["GET", "POST"])
|
||||||
|
def login():
|
||||||
|
if flask.request.method == "POST":
|
||||||
|
username = flask.request.form.get("username")
|
||||||
|
password = flask.request.form.get("password")
|
||||||
|
user = moviedb_func.get_user_by_username(username)
|
||||||
|
if user and user.check_password(password):
|
||||||
|
login_user(user)
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
flash("Ungültiger Benutzername oder Passwort")
|
||||||
|
return render_template("login.html")
|
||||||
|
|
||||||
|
@app.route("/logout")
|
||||||
|
@login_required
|
||||||
|
def logout():
|
||||||
|
logout_user()
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/", methods=["GET", "POST"])
|
||||||
|
@login_required
|
||||||
|
def index():
|
||||||
|
page = flask.request.args.get('page', 1, type=int)
|
||||||
|
per_page = 20
|
||||||
|
search_query = None
|
||||||
|
if flask.request.method == "POST":
|
||||||
|
search_query = flask.request.form.get("search")
|
||||||
|
else:
|
||||||
|
search_query = flask.request.args.get("search")
|
||||||
|
|
||||||
|
data_all, total_pages = moviedb_func.show_movie_list(user_id=current_user.id, search_query=search_query, page=page, per_page=per_page)
|
||||||
|
return render_template(
|
||||||
|
"index.html",
|
||||||
|
sitename="Meine Movieliste !!!",
|
||||||
|
data_all=data_all,
|
||||||
|
total_pages=total_pages,
|
||||||
|
current_page=page,
|
||||||
|
search_query=search_query
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/add_movie")
|
@app.get("/add_movie")
|
||||||
def add_movie():
|
def add_movie():
|
||||||
return flask.render_template(
|
return render_template(
|
||||||
"add_movie.html",
|
"add_movie.html",
|
||||||
sitename="Meine Movieliste !!!",
|
sitename="Meine Movieliste !!!",
|
||||||
url="output",
|
url="output",
|
||||||
select_movie="add_movie",
|
select_movie="add_movie",
|
||||||
select_genre="add_genre",
|
select_genre="add_genre",
|
||||||
select_medium="add_medium",
|
select_medium="add_medium",
|
||||||
select_regie="add_regie",
|
|
||||||
data=moviedb_func.all_select(),
|
data=moviedb_func.all_select(),
|
||||||
data_medium=moviedb_func.all_select(what_select="medium"),
|
data_medium=moviedb_func.all_select(what_select="medium")
|
||||||
data_regie=moviedb_func.all_select(what_select="regie"),
|
|
||||||
data_all=moviedb_func.show_movie_list()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/output")
|
@app.post("/output")
|
||||||
|
@login_required
|
||||||
def csv_output():
|
def csv_output():
|
||||||
select_add_movie = flask.request.form["add_movie"]
|
select_add_movie = flask.request.form["add_movie"]
|
||||||
select_genre = flask.request.form["add_genre"]
|
|
||||||
select_genre_id = moviedb_func.search_id(
|
|
||||||
search_name=flask.request.form["add_genre"])
|
|
||||||
|
|
||||||
select_medium = flask.request.form["add_medium"]
|
select_medium = flask.request.form["add_medium"]
|
||||||
select_medium_id = moviedb_func.search_id(
|
select_medium_id = moviedb_func.search_id(
|
||||||
search_name=flask.request.form["add_medium"], select_from="medium", select_where="medium")
|
search_name=select_medium, select_from="medium", select_where="medium")
|
||||||
select_regie = flask.request.form["add_regie"]
|
|
||||||
select_regie_id = moviedb_func.search_id(
|
|
||||||
search_name=flask.request.form["add_regie"], select_from="regie", select_where="regie")
|
|
||||||
|
|
||||||
moviedb_func.add_movie_to_list(movie_name=select_add_movie, regie_id=select_regie_id,
|
if moviedb_func.scrape_and_add_movie(movie_name=select_add_movie,
|
||||||
medium_id=select_medium_id, genre_id=select_genre_id)
|
medium_id=select_medium_id, user_id=current_user.id):
|
||||||
|
return redirect(url_for('index'))
|
||||||
|
else:
|
||||||
|
return redirect(url_for('add_movie_manually', movie_name=select_add_movie, medium_id=select_medium_id))
|
||||||
|
|
||||||
return flask.render_template(
|
@app.get("/add_movie_manually")
|
||||||
"output.html",
|
@login_required
|
||||||
sitename="Meine Movieliste !!!",
|
def add_movie_manually():
|
||||||
add_movie=select_add_movie,
|
movie_name = flask.request.args.get('movie_name')
|
||||||
add_genre=select_genre,
|
medium_id = flask.request.args.get('medium_id')
|
||||||
add_medium=select_medium,
|
return render_template(
|
||||||
add_regie=select_regie,
|
"add_movie_manually.html",
|
||||||
add_genre_id=select_genre_id,
|
sitename="Manuelle Eingabe",
|
||||||
add_medium_id=select_medium_id,
|
movie_name=movie_name,
|
||||||
add_regie_id=select_regie_id
|
medium_id=medium_id
|
||||||
# data=modify_csv.read_csv_file(),
|
|
||||||
# sum_all=modify_csv.sum_all(),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app.post("/save_manual")
|
||||||
|
@login_required
|
||||||
|
def save_manual():
|
||||||
|
movie_name = flask.request.form["movie_name"]
|
||||||
|
medium_id = flask.request.form["medium_id"]
|
||||||
|
director_name = flask.request.form["director_name"]
|
||||||
|
release_year = flask.request.form["release_year"]
|
||||||
|
genre_name = flask.request.form["genre_name"]
|
||||||
|
|
||||||
|
moviedb_func.add_manual_movie(movie_name=movie_name, medium_id=int(medium_id), director_name=director_name, release_year=int(release_year), genre_name=genre_name, user_id=current_user.id)
|
||||||
|
|
||||||
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(port=5082, host="0.0.0.0", debug=True)
|
moviedb_func.create_movie_database()
|
||||||
|
app.run(port=5082, host="0.0.0.0", debug=True, ssl_context=('cert.pem', 'key.pem'))
|
||||||
|
|||||||
Binary file not shown.
+275
-23
@@ -2,17 +2,103 @@ import DBcm
|
|||||||
from mariadb import ProgrammingError
|
from mariadb import ProgrammingError
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
import urllib.request
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import ssl
|
||||||
|
import imdb_suche
|
||||||
|
from werkzeug.security import generate_password_hash, check_password_hash
|
||||||
|
from flask_login import UserMixin
|
||||||
|
|
||||||
|
|
||||||
|
def get_movie_details(imdb_url):
|
||||||
|
"""
|
||||||
|
Ruft eine IMDb-Filmseite auf und extrahiert den Regisseur und die Hauptdarsteller.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
imdb_url (str): Die vollständige URL zur IMDb-Filmseite.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Ein Wörterbuch mit "director" und "actors" oder None bei einem Fehler.
|
||||||
|
"""
|
||||||
|
if not re.match(r"https://www.imdb.com/de/title/tt\d+/?", imdb_url):
|
||||||
|
print(f"Fehler: Ungültige IMDb-URL: {imdb_url}. Die URL sollte so aussehen: https://www.imdb.com/de/title/tt...")
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# SSL-Kontext erstellen, um Zertifikatsüberprüfungsfehler zu umgehen
|
||||||
|
context = ssl._create_unverified_context()
|
||||||
|
|
||||||
|
# User-Agent setzen, um wie ein Browser auszusehen und Blockaden zu vermeiden
|
||||||
|
headers = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}
|
||||||
|
|
||||||
|
req = urllib.request.Request(imdb_url, headers=headers)
|
||||||
|
|
||||||
|
with urllib.request.urlopen(req, context=context) as response:
|
||||||
|
html_content = response.read().decode('utf-8')
|
||||||
|
|
||||||
|
# Suchen Sie nach dem strukturierten Datenblock (JSON-LD), der Filminformationen enthält
|
||||||
|
match = re.search(
|
||||||
|
r'<script type="application/ld\+json">(.*?)</script>', html_content, re.DOTALL)
|
||||||
|
|
||||||
|
if not match:
|
||||||
|
print("Fehler: Konnte den JSON-LD-Datenblock auf der Seite nicht finden.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
json_data = json.loads(match.group(1))
|
||||||
|
|
||||||
|
# Extrahieren des Regisseurs
|
||||||
|
director = [d.get('name') for d in json_data.get("director", [])] if isinstance(
|
||||||
|
json_data.get("director"), list) else [json_data.get("director", {}).get("name")]
|
||||||
|
|
||||||
|
# Extrahieren der Schauspieler
|
||||||
|
actors = [a.get('name') for a in json_data.get("actor", [])]
|
||||||
|
|
||||||
|
# Extrahieren des Erscheinungsjahres
|
||||||
|
release_year = json_data.get("datePublished", "").split("-")[0]
|
||||||
|
|
||||||
|
# Extrahieren des Genres
|
||||||
|
genre = json_data.get("genre", [])
|
||||||
|
if isinstance(genre, list):
|
||||||
|
genre = ", ".join(genre)
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
"director": [d for d in director if d],
|
||||||
|
"actors": [a for a in actors if a],
|
||||||
|
"release_year": release_year,
|
||||||
|
"genre": genre
|
||||||
|
}
|
||||||
|
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
print(f"HTTP-Fehler beim Abrufen der URL: {e.code} {e.reason}")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ein Fehler ist aufgetreten: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def create_movie_database(db_name="movie_db.db"):
|
def create_movie_database(db_name="movie_db.db"):
|
||||||
|
|
||||||
|
create_user_table = """
|
||||||
|
CREATE TABLE IF NOT EXISTS user (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
username VARCHAR(64) NOT NULL UNIQUE,
|
||||||
|
password_hash VARCHAR(128) NOT NULL
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
|
||||||
create_my_list = """
|
create_my_list = """
|
||||||
create table if not exists movie_list (
|
create table if not exists movie_list (
|
||||||
id integer not null primary key autoincrement,
|
id integer not null primary key autoincrement,
|
||||||
titel varchar(64) not null,
|
titel varchar(64) not null,
|
||||||
genre_id integer not null,
|
genre_id integer not null,
|
||||||
regie_id integer not null,
|
regie_id integer,
|
||||||
medium_id integer not null
|
medium_id integer not null,
|
||||||
|
release_year integer,
|
||||||
|
user_id integer not null,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES user (id)
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -60,6 +146,7 @@ def create_movie_database(db_name="movie_db.db"):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
with DBcm.UseDatabase(db_name) as db:
|
with DBcm.UseDatabase(db_name) as db:
|
||||||
|
db.execute(create_user_table)
|
||||||
db.execute(create_my_list)
|
db.execute(create_my_list)
|
||||||
db.execute(create_genre)
|
db.execute(create_genre)
|
||||||
db.execute(create_regie)
|
db.execute(create_regie)
|
||||||
@@ -104,7 +191,39 @@ def all_select(db_name="movie_db.db", what_select="genre"):
|
|||||||
return "Wrong Value !!!"
|
return "Wrong Value !!!"
|
||||||
|
|
||||||
|
|
||||||
def search_id(db_name="movie_db.db", search_name=str, select_from="genre", select_where="name"):
|
def get_or_create_regie(director_name: str, db_name: str = "movie_db.db"):
|
||||||
|
ADD_REGIE_VALUE = """
|
||||||
|
INSERT INTO regie (surname, lastname )
|
||||||
|
SELECT ?, ?
|
||||||
|
WHERE NOT EXISTS
|
||||||
|
(SELECT surname, lastname
|
||||||
|
FROM regie
|
||||||
|
WHERE surname = ? AND lastname = ?);
|
||||||
|
"""
|
||||||
|
director_split = director_name.split(" ")
|
||||||
|
surname = director_split[0]
|
||||||
|
lastname = " ".join(director_split[1:])
|
||||||
|
with DBcm.UseDatabase(db_name) as db:
|
||||||
|
db.execute(ADD_REGIE_VALUE, (surname, lastname, surname, lastname))
|
||||||
|
db.execute("SELECT id FROM regie WHERE surname = ? AND lastname = ?", (surname, lastname))
|
||||||
|
regie_id = db.fetchone()[0]
|
||||||
|
return regie_id
|
||||||
|
|
||||||
|
|
||||||
|
def get_or_create_genre(genre_name: str, db_name: str = "movie_db.db"):
|
||||||
|
ADD_GENRE_VALUE = """
|
||||||
|
INSERT INTO genre(name)
|
||||||
|
SELECT ?
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM genre WHERE name = ?);
|
||||||
|
"""
|
||||||
|
with DBcm.UseDatabase(db_name) as db:
|
||||||
|
db.execute(ADD_GENRE_VALUE, (genre_name, genre_name))
|
||||||
|
db.execute("SELECT id FROM genre WHERE name = ?", (genre_name,))
|
||||||
|
genre_id = db.fetchone()[0]
|
||||||
|
return genre_id
|
||||||
|
|
||||||
|
|
||||||
|
def search_id(search_name: str, select_from: str = "genre", select_where: str = "name", db_name: str = "movie_db.db"):
|
||||||
if select_from == "regie":
|
if select_from == "regie":
|
||||||
split_search = search_name.split(" ")
|
split_search = search_name.split(" ")
|
||||||
GENRE_QUERY = f"""select id from {select_from}
|
GENRE_QUERY = f"""select id from {select_from}
|
||||||
@@ -125,43 +244,176 @@ def search_id(db_name="movie_db.db", search_name=str, select_from="genre", selec
|
|||||||
return int(0)
|
return int(0)
|
||||||
|
|
||||||
|
|
||||||
def add_movie_to_list(db_name="movie_db.db", movie_name=str, genre_id=int, regie_id=int, medium_id=int):
|
def scrape_and_add_movie(movie_name: str, medium_id: int, user_id: int, db_name: str = "movie_db.db"):
|
||||||
|
url = imdb_suche.suche_film_url(movie_name)
|
||||||
|
if not url:
|
||||||
|
return False
|
||||||
|
|
||||||
|
details = get_movie_details(url + "/")
|
||||||
|
if not details:
|
||||||
|
return False
|
||||||
|
|
||||||
|
regie_id = None
|
||||||
|
if details.get("director"):
|
||||||
|
regie_id = get_or_create_regie(director_name=details["director"][0])
|
||||||
|
|
||||||
|
release_year = details.get("release_year")
|
||||||
|
genre_name = details.get("genre")
|
||||||
|
genre_id = None
|
||||||
|
if genre_name:
|
||||||
|
genre_id = get_or_create_genre(genre_name=genre_name)
|
||||||
|
|
||||||
SQL_PARAM = f"""
|
SQL_PARAM = f"""
|
||||||
INSERT INTO movie_list (titel, genre_id, regie_id, medium_id )
|
INSERT INTO movie_list (titel, genre_id, regie_id, medium_id, release_year, user_id)
|
||||||
SELECT ?, ?, ?, ?
|
VALUES (?, ?, ?, ?, ?, ?);
|
||||||
WHERE NOT EXISTS
|
|
||||||
(SELECT titel FROM movie_list WHERE titel = ?);
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
with DBcm.UseDatabase(db_name) as db:
|
with DBcm.UseDatabase(db_name) as db:
|
||||||
db.execute(SQL_PARAM, (movie_name.lower(), genre_id,
|
db.execute(SQL_PARAM, (movie_name.lower(), genre_id,
|
||||||
regie_id, medium_id, movie_name.lower(),))
|
regie_id, medium_id, release_year, user_id,))
|
||||||
except ProgrammingError:
|
except ProgrammingError as e:
|
||||||
raise ProgrammingError("Konnte nicht in die DB schreiben")
|
print(f"Error adding movie: {e}")
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def show_movie_list(db_name="movie_db.db"):
|
def add_manual_movie(movie_name: str, medium_id: int, director_name: str, release_year: int, genre_name: str, user_id: int, db_name: str = "movie_db.db"):
|
||||||
|
regie_id = get_or_create_regie(director_name=director_name)
|
||||||
|
genre_id = get_or_create_genre(genre_name=genre_name)
|
||||||
|
|
||||||
|
SQL_PARAM = f"""
|
||||||
|
INSERT INTO movie_list (titel, genre_id, regie_id, medium_id, release_year, user_id)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?);
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with DBcm.UseDatabase(db_name) as db:
|
||||||
|
db.execute(SQL_PARAM, (movie_name.lower(), genre_id,
|
||||||
|
regie_id, medium_id, release_year, user_id,))
|
||||||
|
except ProgrammingError as e:
|
||||||
|
print(f"Error adding movie: {e}")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def show_movie_list(db_name="movie_db.db", user_id=None, search_query=None, page=1, per_page=20):
|
||||||
|
"""Zeigt eine paginierte Liste von Filmen an, die nach einem Suchbegriff gefiltert werden können."""
|
||||||
|
|
||||||
|
# Basis-SQL-Abfrage
|
||||||
|
SQL_BASE = """FROM movie_list
|
||||||
|
INNER JOIN genre ON movie_list.genre_id=genre.id
|
||||||
|
INNER JOIN regie ON movie_list.regie_id=regie.id
|
||||||
|
INNER JOIN medium ON movie_list.medium_id=medium.id"""
|
||||||
|
|
||||||
|
# Filter-Bedingungen
|
||||||
|
params = []
|
||||||
|
where_clauses = []
|
||||||
|
if user_id:
|
||||||
|
where_clauses.append("movie_list.user_id = ?")
|
||||||
|
params.append(user_id)
|
||||||
|
|
||||||
|
if search_query:
|
||||||
|
search_param = f"%{search_query}%"
|
||||||
|
where_clauses.append("(titel LIKE ? OR genre.name LIKE ? OR (regie.surname || ' ' || regie.lastname) LIKE ?)")
|
||||||
|
params.extend([search_param, search_param, search_param])
|
||||||
|
|
||||||
|
SQL_WHERE = ""
|
||||||
|
if where_clauses:
|
||||||
|
SQL_WHERE = " WHERE " + " AND ".join(where_clauses)
|
||||||
|
|
||||||
|
# Verbindung zur Datenbank
|
||||||
|
db = sqlite3.connect(db_name)
|
||||||
|
|
||||||
|
# Gesamtzahl der Filme für die Paginierung ermitteln
|
||||||
|
COUNT_SQL = f"SELECT COUNT(movie_list.id) {SQL_BASE}{SQL_WHERE}"
|
||||||
|
total_movies = db.execute(COUNT_SQL, params).fetchone()[0]
|
||||||
|
total_pages = (total_movies + per_page - 1) // per_page
|
||||||
|
|
||||||
|
# Filme für die aktuelle Seite abrufen
|
||||||
|
offset = (page - 1) * per_page
|
||||||
|
SELECT_SQL = f"""SELECT
|
||||||
|
movie_list.id,
|
||||||
|
titel,
|
||||||
|
genre.name AS genre,
|
||||||
|
regie.surname as regie_surname,
|
||||||
|
regie.lastname as regie_lastname,
|
||||||
|
medium.medium,
|
||||||
|
movie_list.release_year
|
||||||
|
{SQL_BASE}{SQL_WHERE}
|
||||||
|
LIMIT ? OFFSET ?"""
|
||||||
|
|
||||||
|
paginated_params = params + [per_page, offset]
|
||||||
|
SELCET_VALUE = pd.read_sql(SELECT_SQL, db, params=paginated_params)
|
||||||
|
|
||||||
|
# Ergebnis in eine Liste von Dictionaries umwandeln
|
||||||
|
return_list_dict = []
|
||||||
|
for id, titel, genre, regie_surname, regie_lastname, medium, release_year in zip(SELCET_VALUE["id"], SELCET_VALUE["titel"], SELCET_VALUE["genre"], SELCET_VALUE["regie_surname"], SELCET_VALUE["regie_lastname"], SELCET_VALUE["medium"], SELCET_VALUE["release_year"]):
|
||||||
|
return_list_dict.append(
|
||||||
|
{"id": id, "titel": titel, "genre": genre, "regie": regie_surname + " " + regie_lastname, "medium": medium, "release_year": release_year})
|
||||||
|
|
||||||
|
return return_list_dict, total_pages
|
||||||
|
|
||||||
|
|
||||||
|
def get_movie_by_title(movie_title: str, db_name: str = "movie_db.db"):
|
||||||
SQL_PARAM = f"""SELECT
|
SQL_PARAM = f"""SELECT
|
||||||
movie_list.id,
|
movie_list.id,
|
||||||
titel,
|
titel,
|
||||||
genre.name AS genre,
|
genre.name AS genre,
|
||||||
regie.surname as regie_surname,
|
regie.surname as regie_surname,
|
||||||
regie.lastname as regie_lastname,
|
regie.lastname as regie_lastname,
|
||||||
medium.medium
|
medium.medium,
|
||||||
|
movie_list.release_year
|
||||||
FROM movie_list
|
FROM movie_list
|
||||||
INNER JOIN genre ON movie_list.genre_id=genre.id
|
INNER JOIN genre ON movie_list.genre_id=genre.id
|
||||||
INNER JOIN regie ON movie_list.regie_id=regie.id
|
INNER JOIN regie ON movie_list.regie_id=regie.id
|
||||||
INNER JOIN medium ON movie_list.medium_id=medium.id
|
INNER JOIN medium ON movie_list.medium_id=medium.id
|
||||||
|
WHERE movie_list.titel = ?
|
||||||
;
|
;
|
||||||
"""
|
"""
|
||||||
db = sqlite3.connect(db_name)
|
with DBcm.UseDatabase(db_name) as db:
|
||||||
SELCET_VALUE = pd.read_sql(SQL_PARAM, db)
|
db.execute(SQL_PARAM, (movie_title.lower(),))
|
||||||
return_list_dict = []
|
movie = db.fetchone()
|
||||||
for id, titel, genre, regie_surname, regie_lastname, medium in zip(SELCET_VALUE["id"], SELCET_VALUE["titel"], SELCET_VALUE["genre"], SELCET_VALUE["regie_surname"], SELCET_VALUE["regie_lastname"], SELCET_VALUE["medium"]):
|
if movie:
|
||||||
return_list_dict.append(
|
return {"id": movie[0], "titel": movie[1], "genre": movie[2], "regie": movie[3] + " " + movie[4], "medium": movie[5], "release_year": movie[6]}
|
||||||
{"id": id, "titel": titel, "genre": genre, "regie": regie_surname + " " + regie_lastname, "medium": medium})
|
return None
|
||||||
return return_list_dict
|
|
||||||
|
class User(UserMixin):
|
||||||
|
def __init__(self, id, username, password_hash):
|
||||||
|
self.id = id
|
||||||
|
self.username = username
|
||||||
|
self.password_hash = password_hash
|
||||||
|
|
||||||
|
def set_password(self, password):
|
||||||
|
self.password_hash = generate_password_hash(password)
|
||||||
|
|
||||||
|
def check_password(self, password):
|
||||||
|
return check_password_hash(self.password_hash, password)
|
||||||
|
|
||||||
|
|
||||||
|
def add_user(username, password, db_name="movie_db.db"):
|
||||||
|
password_hash = generate_password_hash(password)
|
||||||
|
SQL = "INSERT INTO user (username, password_hash) VALUES (?, ?)"
|
||||||
|
with DBcm.UseDatabase(db_name) as db:
|
||||||
|
db.execute(SQL, (username, password_hash))
|
||||||
|
|
||||||
|
def get_user_by_username(username, db_name="movie_db.db"):
|
||||||
|
SQL = "SELECT * FROM user WHERE username = ?"
|
||||||
|
with DBcm.UseDatabase(db_name) as db:
|
||||||
|
db.execute(SQL, (username,))
|
||||||
|
user_data = db.fetchone()
|
||||||
|
if user_data:
|
||||||
|
return User(id=user_data[0], username=user_data[1], password_hash=user_data[2])
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_by_id(user_id, db_name="movie_db.db"):
|
||||||
|
SQL = "SELECT * FROM user WHERE id = ?"
|
||||||
|
with DBcm.UseDatabase(db_name) as db:
|
||||||
|
db.execute(SQL, (user_id,))
|
||||||
|
user_data = db.fetchone()
|
||||||
|
if user_data:
|
||||||
|
return User(id=user_data[0], username=user_data[1], password_hash=user_data[2])
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
@@ -169,7 +421,7 @@ if __name__ == "__main__":
|
|||||||
# print(all_select())
|
# print(all_select())
|
||||||
# id_genre = search_id(
|
# id_genre = search_id(
|
||||||
# search_name="DVD", select_from="medium", select_where="medium")
|
# search_name="DVD", select_from="medium", select_where="medium")
|
||||||
add_movie_to_list(movie_name="Schlumpfland",
|
scrape_and_add_movie(movie_name="Die unglaubliche Reise in einem verrückten Flugzeug",
|
||||||
genre_id=1, regie_id=1, medium_id=1)
|
medium_id=1)
|
||||||
for test in show_movie_list():
|
for test in show_movie_list():
|
||||||
print(test.get("id"), test.get("medium"))
|
print(test.get("id"), test.get("medium"), test.get("release_year"))
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
flask
|
flask
|
||||||
dbcm
|
dbcm
|
||||||
|
pandas
|
||||||
|
requests
|
||||||
|
beautifulsoup4
|
||||||
|
Flask-Login
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy and start Movie-DB Application
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
vars:
|
||||||
|
project_name: movie-db
|
||||||
|
install_dir: "/opt/{{ project_name }}"
|
||||||
|
project_src: "{{ playbook_dir }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create installation directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ install_dir }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Copy docker-compose file
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "{{ project_src }}/docker-compose.yml"
|
||||||
|
dest: "{{ install_dir }}/docker-compose.yml"
|
||||||
|
|
||||||
|
- name: Start application with Docker Compose
|
||||||
|
community.docker.docker_compose:
|
||||||
|
project_src: "{{ install_dir }}"
|
||||||
|
state: present
|
||||||
|
restarted: yes
|
||||||
@@ -1,50 +1,20 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<form action="{{ url }}" method="POST">
|
<form action="{{ url }}" method="POST" class="mb-3">
|
||||||
|
<div class="mb-3">
|
||||||
<input type="text"
|
<input type="text"
|
||||||
|
class="form-control"
|
||||||
placeholder="Movie"
|
placeholder="Movie"
|
||||||
name="{{ select_movie }}"
|
name="{{ select_movie }}"
|
||||||
id="{{ select_movie }}">
|
id="{{ select_movie }}">
|
||||||
|
</div>
|
||||||
<select name="{{ select_genre }}" id="{{ select_genre }}">
|
<div class="mb-3">
|
||||||
{% for name in data %}
|
<select name="{{ select_medium }}" id="{{ select_medium }}" class="form-select">
|
||||||
<option value="{{ name }}">{{ name }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select name="{{ select_medium }}" id="{{ select_medium }}">
|
|
||||||
{% for name in data_medium %}
|
{% for name in data_medium %}
|
||||||
<option value="{{ name }}">{{ name }}</option>
|
<option value="{{ name }}">{{ name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
<select name="{{ select_regie }}" id="{{ select_regie }}">
|
<button type="submit" class="btn btn-primary">Eingabe</button>
|
||||||
{% for name in data_regie %}
|
|
||||||
<option value="{{ name }}">{{ name }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<button type="submit"> Eingabe </button>
|
|
||||||
</form>
|
</form>
|
||||||
<br>
|
|
||||||
|
|
||||||
<table border="1" width="50%">
|
|
||||||
<tr>
|
|
||||||
<th>Id</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Genre</th>
|
|
||||||
<th>Regie</th>
|
|
||||||
<th>Medium</th>
|
|
||||||
</tr>
|
|
||||||
{% for list_all in data_all %}
|
|
||||||
<tr>
|
|
||||||
<td>{{list_all.get("id")}}</td>
|
|
||||||
<td>{{list_all.get("titel")}}</td>
|
|
||||||
<td>{{list_all.get("genre")}}</td>
|
|
||||||
<td>{{list_all.get("regie")}}</td>
|
|
||||||
<td>{{list_all.get("medium")}}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<h3 class="mb-3">Film nicht gefunden. Bitte manuell eingeben:</h3>
|
||||||
|
<form action="/save_manual" method="POST">
|
||||||
|
<input type="hidden" name="movie_name" value="{{ movie_name }}">
|
||||||
|
<input type="hidden" name="medium_id" value="{{ medium_id }}">
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="genre_name" class="form-label">Genre:</label>
|
||||||
|
<input type="text" class="form-control" id="genre_name" name="genre_name" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="director_name" class="form-label">Regisseur:</label>
|
||||||
|
<input type="text" class="form-control" id="director_name" name="director_name" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="release_year" class="form-label">Erscheinungsjahr:</label>
|
||||||
|
<input type="number" class="form-control" id="release_year" name="release_year" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Speichern</button>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,12 +1,36 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html>
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>{{ sitename }}</title>
|
<title>{{ sitename }}</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h2> {{ sitename }} </h2>
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
<p> Es werden alle Filmtitel in einer Liste angezeigt.
|
<div class="container-fluid">
|
||||||
{% block body %}
|
<a class="navbar-brand" href="{{ url_for('index') }}">{{ sitename }}</a>
|
||||||
{% endblock %}
|
<div class="collapse navbar-collapse">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url_for('logout') }}">Logout</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url_for('login') }}">Login</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{{ url_for('register') }}">Registrieren</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class="container mt-4">
|
||||||
|
{% block body %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<a href="/add_movie" class="btn btn-primary mb-3">Film hinzufügen</a>
|
||||||
|
|
||||||
|
<form method="post" action="{{ url_for('index') }}">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col">
|
||||||
|
<label for="search" class="form-label">Suche</label>
|
||||||
|
<input type="text" name="search" id="search" class="form-control" value="{{ search_query }}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Suchen</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<table class="table table-striped table-bordered mt-3">
|
||||||
|
<thead class="table-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Id</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Genre</th>
|
||||||
|
<th>Regie</th>
|
||||||
|
<th>Medium</th>
|
||||||
|
<th>Erscheinungsjahr</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for list_all in data_all %}
|
||||||
|
<tr>
|
||||||
|
<td>{{list_all.get("id")}}</td>
|
||||||
|
<td>{{list_all.get("titel")}}</td>
|
||||||
|
<td>{{list_all.get("genre")}}</td>
|
||||||
|
<td>{{list_all.get("regie")}}</td>
|
||||||
|
<td>{{list_all.get("medium")}}</td>
|
||||||
|
<td>{{list_all.get("release_year")}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<nav aria-label="Page navigation">
|
||||||
|
<ul class="pagination">
|
||||||
|
<li class="page-item {% if current_page == 1 %}disabled{% endif %}">
|
||||||
|
<a class="page-link" href="{{ url_for('index', page=1, search=search_query) }}">Erste</a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item {% if current_page == 1 %}disabled{% endif %}">
|
||||||
|
<a class="page-link" href="{{ url_for('index', page=current_page - 1, search=search_query) }}">Zurück</a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<a class="page-link" href="#">Seite {{ current_page }} von {{ total_pages }}</a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item {% if current_page == total_pages %}disabled{% endif %}">
|
||||||
|
<a class="page-link" href="{{ url_for('index', page=current_page + 1, search=search_query) }}">Weiter</a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item {% if current_page == total_pages %}disabled{% endif %}">
|
||||||
|
<a class="page-link" href="{{ url_for('index', page=total_pages, search=search_query) }}">Letzte</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<div class="container">
|
||||||
|
<h2>Login</h2>
|
||||||
|
{% with messages = get_flashed_messages() %}
|
||||||
|
{% if messages %}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
{{ messages[0] }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
<form method="post">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="username" class="form-label">Benutzername</label>
|
||||||
|
<input type="text" class="form-control" id="username" name="username" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">Passwort</label>
|
||||||
|
<input type="password" class="form-control" id="password" name="password" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Login</button>
|
||||||
|
</form>
|
||||||
|
<p class="mt-3">Noch keinen Account? <a href="{{ url_for('register') }}">Hier registrieren</a>.</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
<p>
|
|
||||||
Film = {{ add_movie }} <br>
|
|
||||||
Genre = {{ add_genre }} <span>  genre_id = {{ add_genre_id }} <br>
|
|
||||||
Medium = {{ add_medium }} <span>  medium_id = {{add_medium_id }} <br>
|
|
||||||
Regie = {{ add_regie }} <span>  reg_id = {{ add_regie_id }} <br>
|
|
||||||
</p>
|
|
||||||
{% endblock %}
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<div class="container">
|
||||||
|
<h2>Registrieren</h2>
|
||||||
|
<form method="post">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="username" class="form-label">Benutzername</label>
|
||||||
|
<input type="text" class="form-control" id="username" name="username" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">Passwort</label>
|
||||||
|
<input type="password" class="form-control" id="password" name="password" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Registrieren</button>
|
||||||
|
</form>
|
||||||
|
<p class="mt-3">Schon einen Account? <a href="{{ url_for('login') }}">Hier einloggen</a>.</p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -1,650 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 1,
|
|
||||||
"id": "5263a987-da36-46d7-a2e7-d0658cda09c1",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import DBcm"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 2,
|
|
||||||
"id": "3f6b0763-4106-4bfa-9aef-7afbd180c6d4",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"db_name = \"movie_db.db\"\n",
|
|
||||||
"\n",
|
|
||||||
"create_my_list = \"\"\"\n",
|
|
||||||
" create table if not exists movie_list (\n",
|
|
||||||
" id integer not null primary key autoincrement,\n",
|
|
||||||
" titel varchar(64) not null,\n",
|
|
||||||
" genre_id integer not null,\n",
|
|
||||||
" regie_id integer not null\n",
|
|
||||||
" \n",
|
|
||||||
" )\n",
|
|
||||||
"\n",
|
|
||||||
"\"\"\"\n",
|
|
||||||
"\n",
|
|
||||||
"create_genre = \"\"\"\n",
|
|
||||||
" create table if not exists genre (\n",
|
|
||||||
" id integer not null primary key autoincrement,\n",
|
|
||||||
" name varchar(64) not null\n",
|
|
||||||
" )\n",
|
|
||||||
"\"\"\"\n",
|
|
||||||
"\n",
|
|
||||||
"create_regie = \"\"\"\n",
|
|
||||||
" create table if not exists regie (\n",
|
|
||||||
" id integer not null primary key autoincrement,\n",
|
|
||||||
" surname varchar(64) not null,\n",
|
|
||||||
" lastname varchr(64) not null\n",
|
|
||||||
" )\n",
|
|
||||||
"\"\"\"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"with DBcm.UseDatabase(db_name) as db: \n",
|
|
||||||
" db.execute(create_my_list)\n",
|
|
||||||
" db.execute(create_genre)\n",
|
|
||||||
" db.execute(create_regie)\n",
|
|
||||||
" "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 3,
|
|
||||||
"id": "376ef812-97b5-45ba-8ef1-eb8d7829494a",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# ADDed Genre values\n",
|
|
||||||
"\n",
|
|
||||||
"ADD_GENRE_VALUE = \"\"\"\n",
|
|
||||||
" INSERT INTO genre(name)\n",
|
|
||||||
" SELECT ?\n",
|
|
||||||
" WHERE NOT EXISTS (SELECT 1 FROM genre WHERE name = ?);\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
"\n",
|
|
||||||
"with open(\"genre_list\", \"r\") as fs: \n",
|
|
||||||
" for genre_value in fs.readlines():\n",
|
|
||||||
" with DBcm.UseDatabase(db_name) as db:\n",
|
|
||||||
" db.execute(ADD_GENRE_VALUE, (genre_value.strip(), genre_value.strip()))\n",
|
|
||||||
" "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 27,
|
|
||||||
"id": "63b16a41-88bf-4832-a26c-09180832f597",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"['action', 'adventure', 'animation', 'biography', 'comedy', 'crime', 'cult movie', 'disney', 'documentary', 'drama', 'erotic', 'family', 'fantasy', 'film-noir', 'gangster', 'gay and lesbian', 'history', 'horror', 'military', 'music', 'musical', 'mystery', 'nature', 'neo-noir', 'period', 'pixar', 'road movie', 'romance', 'sci-fi', 'short', 'spy', 'super hero', 'thriller', 'visually stunning', 'war', 'western']\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"def all_genres():\n",
|
|
||||||
" ALL_GENRE = \"\"\"\n",
|
|
||||||
" SELECT * from genre \n",
|
|
||||||
" \"\"\" \n",
|
|
||||||
" with DBcm.UseDatabase(db_name) as db:\n",
|
|
||||||
" db.execute(ALL_GENRE)\n",
|
|
||||||
" all_genre = [i[1] for i in db.fetchall()]\n",
|
|
||||||
" \n",
|
|
||||||
" return all_genre\n",
|
|
||||||
"\n",
|
|
||||||
"print(all_genres())\n",
|
|
||||||
" "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 36,
|
|
||||||
"id": "89b20b5f-34aa-4490-a4c0-c186c9fa30bd",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"1\n",
|
|
||||||
"36\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"def search_genre_id(genre_name):\n",
|
|
||||||
" GENRE_QUERY = \"\"\"\n",
|
|
||||||
" select id from genre\n",
|
|
||||||
" where name = ?\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" try:\n",
|
|
||||||
" with DBcm.UseDatabase(db_name) as db:\n",
|
|
||||||
" db.execute(GENRE_QUERY,(genre_name,))\n",
|
|
||||||
" genre_id = db.fetchone()[0]\n",
|
|
||||||
" return int(genre_id)\n",
|
|
||||||
" except:\n",
|
|
||||||
" return int(0)\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def search_medium_id(genre_name):\n",
|
|
||||||
" GENRE_QUERY = \"\"\"\n",
|
|
||||||
" select id from genre\n",
|
|
||||||
" where medium = ?\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" try:\n",
|
|
||||||
" with DBcm.UseDatabase(db_name) as db:\n",
|
|
||||||
" db.execute(GENRE_QUERY,(genre_name,))\n",
|
|
||||||
" genre_id = db.fetchone()[0]\n",
|
|
||||||
" return int(genre_id)\n",
|
|
||||||
" except:\n",
|
|
||||||
" return int(0)\n",
|
|
||||||
"\n",
|
|
||||||
"print(search_genre_id(genre_name=\"action\"))\n",
|
|
||||||
"print(search_genre_id(genre_name=\"western\"))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 18,
|
|
||||||
"id": "c70d91a5-7855-465d-a4a6-daebc065ee37",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"0-John-Smith\n",
|
|
||||||
"1-James-Johnson\n",
|
|
||||||
"2-William-Williams\n",
|
|
||||||
"3-Michael-Brown\n",
|
|
||||||
"4-David-Davis\n",
|
|
||||||
"5-Richard-Miller\n",
|
|
||||||
"6-Joseph-Wilson\n",
|
|
||||||
"7-Charles-Moore\n",
|
|
||||||
"8-Thomas-Taylor\n",
|
|
||||||
"9-Daniel-Anderson\n",
|
|
||||||
"10-Paul-Thomas\n",
|
|
||||||
"11-Mark-Jackson\n",
|
|
||||||
"12-Donna-White\n",
|
|
||||||
"13-Michelle-Harris\n",
|
|
||||||
"14-Laura-Martin\n",
|
|
||||||
"15-Sara-Thompson\n",
|
|
||||||
"16-Ana-Garcia\n",
|
|
||||||
"17-Carlos-Rodriguez\n",
|
|
||||||
"18-Maria-Martinez\n",
|
|
||||||
"19-Jose-Hernandez\n",
|
|
||||||
"20-Luis-Lopez\n",
|
|
||||||
"21-Rosa-Gonzalez\n",
|
|
||||||
"22-Pedro-Perez\n",
|
|
||||||
"23-Miguel-Sanchez\n",
|
|
||||||
"24-Juan-Ramirez\n",
|
|
||||||
"25-Ana-Flores\n",
|
|
||||||
"26-Isabella-Cruz\n",
|
|
||||||
"27-Victor-Rivera\n",
|
|
||||||
"28-Kevin-Lee\n",
|
|
||||||
"29-Brian-Walker\n",
|
|
||||||
"30-Emily-Hall\n",
|
|
||||||
"31-Ryan-Allen\n",
|
|
||||||
"32-Aaron-Young\n",
|
|
||||||
"33-Jeffrey-King\n",
|
|
||||||
"34-Joshua-Wright\n",
|
|
||||||
"35-Brandon-Scott\n",
|
|
||||||
"36-Frank-Turner\n",
|
|
||||||
"37-Gregory-Carter\n",
|
|
||||||
"38-Samuel-Phillips\n",
|
|
||||||
"39-Chris-Evans\n",
|
|
||||||
"40-Anthony-Collins\n",
|
|
||||||
"41-Eric-Stewart\n",
|
|
||||||
"42-Frank-Snyder\n",
|
|
||||||
"43-Thomas-Baker\n",
|
|
||||||
"44-Jeremy-Nelson\n",
|
|
||||||
"45-Steven-Roberts\n",
|
|
||||||
"46-Edward-Campbell\n",
|
|
||||||
"47-Ryan-Miller\n",
|
|
||||||
"48-Jacob-Davis\n",
|
|
||||||
"49-David-Garcia\n",
|
|
||||||
"50-Sophia-Rodriguez\n",
|
|
||||||
"51-Emma-Martinez\n",
|
|
||||||
"52-Noah-Hernandez\n",
|
|
||||||
"53-Ava-Lopez\n",
|
|
||||||
"54-Ethan-Gonzalez\n",
|
|
||||||
"55-Mia-Perez\n",
|
|
||||||
"56-William-Sanchez\n",
|
|
||||||
"57-James-Ramirez\n",
|
|
||||||
"58-Olivia-Flores\n",
|
|
||||||
"59-Lucas-Cruz\n",
|
|
||||||
"60-Isabella-Rivera\n",
|
|
||||||
"61-David-Lee\n",
|
|
||||||
"62-Sophie-Walker\n",
|
|
||||||
"63-Matthew-Hall\n",
|
|
||||||
"64-Emma-Allen\n",
|
|
||||||
"65-Ryan-Young\n",
|
|
||||||
"66-Ava-King\n",
|
|
||||||
"67-Ethan-Wright\n",
|
|
||||||
"68-Mia-Scott\n",
|
|
||||||
"69-William-Turner\n",
|
|
||||||
"70-James-Carter\n",
|
|
||||||
"71-Olivia-Phillips\n",
|
|
||||||
"72-Lucas-Evans\n",
|
|
||||||
"73-Sophie-Collins\n",
|
|
||||||
"74-Noah-Stewart\n",
|
|
||||||
"75-Ava-Snyder\n",
|
|
||||||
"76-Ethan-Baker\n",
|
|
||||||
"77-Mia-Nelson\n",
|
|
||||||
"78-Noah-Roberts\n",
|
|
||||||
"79-Emma-Campbell\n",
|
|
||||||
"80-William-Miller\n",
|
|
||||||
"81-James-Davis\n",
|
|
||||||
"82-Olivia-Garcia\n",
|
|
||||||
"83-Lucas-Rodriguez\n",
|
|
||||||
"84-Sophie-Martinez\n",
|
|
||||||
"85-Noah-Hernandez\n",
|
|
||||||
"86-Ava-Lopez\n",
|
|
||||||
"87-Ethan-Gonzalez\n",
|
|
||||||
"88-Mia-Perez\n",
|
|
||||||
"89-William-Sanchez\n",
|
|
||||||
"90-James-Ramirez\n",
|
|
||||||
"91-Olivia-Flores\n",
|
|
||||||
"92-Lucas-Cruz\n",
|
|
||||||
"93-Isabella-Rivera\n",
|
|
||||||
"94-David-Lee\n",
|
|
||||||
"95-Sophie-Walker\n",
|
|
||||||
"96-Matthew-Hall\n",
|
|
||||||
"97-Emma-Allen\n",
|
|
||||||
"98-Ryan-Young\n",
|
|
||||||
"99-Ava-King\n",
|
|
||||||
"100-Ethan-Wright\n",
|
|
||||||
"101-Mia-Scott\n",
|
|
||||||
"102-William-Turner\n",
|
|
||||||
"103-James-Carter\n",
|
|
||||||
"104-Olivia-Phillips\n",
|
|
||||||
"105-Lucas-Evans\n",
|
|
||||||
"106-Sophie-Collins\n",
|
|
||||||
"107-Noah-Stewart\n",
|
|
||||||
"108-Ava-Snyder\n",
|
|
||||||
"109-Ethan-Baker\n",
|
|
||||||
"110-Mia-Nelson\n",
|
|
||||||
"111-Noah-Roberts\n",
|
|
||||||
"112-Emma-Campbell\n",
|
|
||||||
"113-William-Miller\n",
|
|
||||||
"114-James-Davis\n",
|
|
||||||
"115-Olivia-Garcia\n",
|
|
||||||
"116-Lucas-Rodriguez\n",
|
|
||||||
"117-Sophie-Martinez\n",
|
|
||||||
"118-Noah-Hernandez\n",
|
|
||||||
"119-Ava-Lopez\n",
|
|
||||||
"120-Ethan-Gonzalez\n",
|
|
||||||
"121-Mia-Perez\n",
|
|
||||||
"122-William-Sanchez\n",
|
|
||||||
"123-James-Ramirez\n",
|
|
||||||
"124-Olivia-Flores\n",
|
|
||||||
"125-Lucas-Cruz\n",
|
|
||||||
"126-Isabella-Rivera\n",
|
|
||||||
"127-David-Lee\n",
|
|
||||||
"128-Sophie-Walker\n",
|
|
||||||
"129-Matthew-Hall\n",
|
|
||||||
"130-Emma-Allen\n",
|
|
||||||
"131-Ryan-Young\n",
|
|
||||||
"132-Ava-King\n",
|
|
||||||
"133-Ethan-Wright\n",
|
|
||||||
"134-Mia-Scott\n",
|
|
||||||
"135-William-Turner\n",
|
|
||||||
"136-James-Carter\n",
|
|
||||||
"137-Olivia-Phillips\n",
|
|
||||||
"138-Lucas-Evans\n",
|
|
||||||
"139-Sophie-Collins\n",
|
|
||||||
"140-Noah-Stewart\n",
|
|
||||||
"141-Ava-Snyder\n",
|
|
||||||
"142-Ethan-Baker\n",
|
|
||||||
"143-Mia-Nelson\n",
|
|
||||||
"144-Noah-Roberts\n",
|
|
||||||
"145-Emma-Campbell\n",
|
|
||||||
"146-William-Miller\n",
|
|
||||||
"147-James-Davis\n",
|
|
||||||
"148-Olivia-Garcia\n",
|
|
||||||
"149-Lucas-Rodriguez\n",
|
|
||||||
"150-Sophie-Martinez\n",
|
|
||||||
"151-Noah-Hernandez\n",
|
|
||||||
"152-Ava-Lopez\n",
|
|
||||||
"153-Ethan-Gonzalez\n",
|
|
||||||
"154-Mia-Perez\n",
|
|
||||||
"155-William-Sanchez\n",
|
|
||||||
"156-James-Ramirez\n",
|
|
||||||
"157-Olivia-Flores\n",
|
|
||||||
"158-Lucas-Cruz\n",
|
|
||||||
"159-Isabella-Rivera\n",
|
|
||||||
"160-David-Lee\n",
|
|
||||||
"161-Sophie-Walker\n",
|
|
||||||
"162-Matthew-Hall\n",
|
|
||||||
"163-Emma-Allen\n",
|
|
||||||
"164-Ryan-Young\n",
|
|
||||||
"165-Ava-King\n",
|
|
||||||
"166-Ethan-Wright\n",
|
|
||||||
"167-Mia-Scott\n",
|
|
||||||
"168-William-Turner\n",
|
|
||||||
"169-James-Carter\n",
|
|
||||||
"170-Olivia-Phillips\n",
|
|
||||||
"171-Lucas-Evans\n",
|
|
||||||
"172-Sophie-Collins\n",
|
|
||||||
"173-Noah-Stewart\n",
|
|
||||||
"174-Ava-Snyder\n",
|
|
||||||
"175-Ethan-Baker\n",
|
|
||||||
"176-Mia-Nelson\n",
|
|
||||||
"177-Noah-Roberts\n",
|
|
||||||
"178-Emma-Campbell\n",
|
|
||||||
"179-William-Miller\n",
|
|
||||||
"180-James-Davis\n",
|
|
||||||
"181-Olivia-Garcia\n",
|
|
||||||
"182-Lucas-Rodriguez\n",
|
|
||||||
"183-Sophie-Martinez\n",
|
|
||||||
"184-Noah-Hernandez\n",
|
|
||||||
"185-Ava-Lopez\n",
|
|
||||||
"186-Ethan-Gonzalez\n",
|
|
||||||
"187-Mia-Perez\n",
|
|
||||||
"188-William-Sanchez\n",
|
|
||||||
"189-James-Ramirez\n",
|
|
||||||
"190-Olivia-Flores\n",
|
|
||||||
"191-Lucas-Cruz\n",
|
|
||||||
"192-Isabella-Rivera\n",
|
|
||||||
"193-David-Lee\n",
|
|
||||||
"194-Sophie-Walker\n",
|
|
||||||
"195-Matthew-Hall\n",
|
|
||||||
"196-Emma-Allen\n",
|
|
||||||
"197-Ryan-Young\n",
|
|
||||||
"198-Ava-King\n",
|
|
||||||
"199-Ethan-Wright\n",
|
|
||||||
"200-Mia-Scott\n",
|
|
||||||
"201-William-Turner\n",
|
|
||||||
"202-James-Carter\n",
|
|
||||||
"203-Olivia-Phillips\n",
|
|
||||||
"204-Lucas-Evans\n",
|
|
||||||
"205-Sophie-Collins\n",
|
|
||||||
"206-Noah-Stewart\n",
|
|
||||||
"207-Ava-Snyder\n",
|
|
||||||
"208-Ethan-Baker\n",
|
|
||||||
"209-Mia-Nelson\n",
|
|
||||||
"210-Noah-Roberts\n",
|
|
||||||
"211-Emma-Campbell\n",
|
|
||||||
"212-William-Miller\n",
|
|
||||||
"213-James-Davis\n",
|
|
||||||
"214-Olivia-Garcia\n",
|
|
||||||
"215-Lucas-Rodriguez\n",
|
|
||||||
"216-Sophie-Martinez\n",
|
|
||||||
"217-Noah-Hernandez\n",
|
|
||||||
"218-Ava-Lopez\n",
|
|
||||||
"219-Ethan-Gonzalez\n",
|
|
||||||
"220-Mia-Perez\n",
|
|
||||||
"221-William-Sanchez\n",
|
|
||||||
"222-James-Ramirez\n",
|
|
||||||
"223-Olivia-Flores\n",
|
|
||||||
"224-Lucas-Cruz\n",
|
|
||||||
"225-Isabella-Rivera\n",
|
|
||||||
"226-David-Lee\n",
|
|
||||||
"227-Sophie-Walker\n",
|
|
||||||
"228-Matthew-Hall\n",
|
|
||||||
"229-Emma-Allen\n",
|
|
||||||
"230-Ryan-Young\n",
|
|
||||||
"231-Ava-King\n",
|
|
||||||
"232-Ethan-Wright\n",
|
|
||||||
"233-Mia-Scott\n",
|
|
||||||
"234-William-Turner\n",
|
|
||||||
"235-James-Carter\n",
|
|
||||||
"236-Olivia-Phillips\n",
|
|
||||||
"237-Lucas-Evans\n",
|
|
||||||
"238-Sophie-Collins\n",
|
|
||||||
"239-Noah-Stewart\n",
|
|
||||||
"240-Ava-Snyder\n",
|
|
||||||
"241-Ethan-Baker\n",
|
|
||||||
"242-Mia-Nelson\n",
|
|
||||||
"243-Noah-Roberts\n",
|
|
||||||
"244-Emma-Campbell\n",
|
|
||||||
"245-William-Miller\n",
|
|
||||||
"246-James-Davis\n",
|
|
||||||
"247-Olivia-Garcia\n",
|
|
||||||
"248-Lucas-Rodriguez\n",
|
|
||||||
"249-Sophie-Martinez\n",
|
|
||||||
"250-Noah-Hernandez\n",
|
|
||||||
"251-Ava-Lopez\n",
|
|
||||||
"252-Ethan-Gonzalez\n",
|
|
||||||
"253-Mia-Perez\n",
|
|
||||||
"254-William-Sanchez\n",
|
|
||||||
"255-James-Ramirez\n",
|
|
||||||
"256-Olivia-Flores\n",
|
|
||||||
"257-Lucas-Cruz\n",
|
|
||||||
"258-Isabella-Rivera\n",
|
|
||||||
"259-David-Lee\n",
|
|
||||||
"260-Sophie-Walker\n",
|
|
||||||
"261-Matthew-Hall\n",
|
|
||||||
"262-Emma-Allen\n",
|
|
||||||
"263-Ryan-Young\n",
|
|
||||||
"264-Ava-King\n",
|
|
||||||
"265-Ethan-Wright\n",
|
|
||||||
"266-Mia-Scott\n",
|
|
||||||
"267-William-Turner\n",
|
|
||||||
"268-James-Carter\n",
|
|
||||||
"269-Olivia-Phillips\n",
|
|
||||||
"270-Lucas-Evans\n",
|
|
||||||
"271-Sophie-Collins\n",
|
|
||||||
"272-Noah-Stewart\n",
|
|
||||||
"273-Ava-Snyder\n",
|
|
||||||
"274-Ethan-Baker\n",
|
|
||||||
"275-Mia-Nelson\n",
|
|
||||||
"276-Noah-Roberts\n",
|
|
||||||
"277-Emma-Campbell\n",
|
|
||||||
"278-William-Miller\n",
|
|
||||||
"279-James-Davis\n",
|
|
||||||
"280-Olivia-Garcia\n",
|
|
||||||
"281-Lucas-Rodriguez\n",
|
|
||||||
"282-Sophie-Martinez\n",
|
|
||||||
"283-Noah-Hernandez\n",
|
|
||||||
"284-Ava-Lopez\n",
|
|
||||||
"285-Ethan-Gonzalez\n",
|
|
||||||
"286-Mia-Perez\n",
|
|
||||||
"287-William-Sanchez\n",
|
|
||||||
"288-James-Ramirez\n",
|
|
||||||
"289-Olivia-Flores\n",
|
|
||||||
"290-Lucas-Cruz\n",
|
|
||||||
"291-Isabella-Rivera\n",
|
|
||||||
"292-David-Lee\n",
|
|
||||||
"293-Sophie-Walker\n",
|
|
||||||
"294-Matthew-Hall\n",
|
|
||||||
"295-Emma-Allen\n",
|
|
||||||
"296-Ryan-Young\n",
|
|
||||||
"297-Ava-King\n",
|
|
||||||
"298-Ethan-Wright\n",
|
|
||||||
"299-Mia-Scott\n",
|
|
||||||
"300-William-Turner\n",
|
|
||||||
"301-James-Carter\n",
|
|
||||||
"302-Olivia-Phillips\n",
|
|
||||||
"303-Lucas-Evans\n",
|
|
||||||
"304-Sophie-Collins\n",
|
|
||||||
"305-Noah-Stewart\n",
|
|
||||||
"306-Ava-Snyder\n",
|
|
||||||
"307-Ethan-Baker\n",
|
|
||||||
"308-Mia-Nelson\n",
|
|
||||||
"309-Noah-Roberts\n",
|
|
||||||
"310-Emma-Campbell\n",
|
|
||||||
"311-William-Miller\n",
|
|
||||||
"312-James-Davis\n",
|
|
||||||
"313-Olivia-Garcia\n",
|
|
||||||
"314-Lucas-Rodriguez\n",
|
|
||||||
"315-Sophie-Martinez\n",
|
|
||||||
"316-Noah-Hernandez\n",
|
|
||||||
"317-Ava-Lopez\n",
|
|
||||||
"318-Ethan-Gonzalez\n",
|
|
||||||
"319-Mia-Perez\n",
|
|
||||||
"320-William-Sanchez\n",
|
|
||||||
"321-James-Ramirez\n",
|
|
||||||
"322-Olivia-Flores\n",
|
|
||||||
"323-Lucas-Cruz\n",
|
|
||||||
"324-Isabella-Rivera\n",
|
|
||||||
"325-David-Lee\n",
|
|
||||||
"326-Sophie-Walker\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"import pandas as pd\n",
|
|
||||||
"usecols = [\"Name\", \"Vorname\"]\n",
|
|
||||||
"air = pd.read_csv(\"regie_name.csv\", usecols=usecols)\n",
|
|
||||||
"\n",
|
|
||||||
"for count, (i, b) in enumerate(zip(air[\"Name\"], air[\"Vorname\"])):\n",
|
|
||||||
" print(count, b, i, sep=\"-\")\n",
|
|
||||||
"\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 3,
|
|
||||||
"id": "ee4b5dee-6b41-49eb-8d75-9db50d20fdef",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<div>\n",
|
|
||||||
"<style scoped>\n",
|
|
||||||
" .dataframe tbody tr th:only-of-type {\n",
|
|
||||||
" vertical-align: middle;\n",
|
|
||||||
" }\n",
|
|
||||||
"\n",
|
|
||||||
" .dataframe tbody tr th {\n",
|
|
||||||
" vertical-align: top;\n",
|
|
||||||
" }\n",
|
|
||||||
"\n",
|
|
||||||
" .dataframe thead th {\n",
|
|
||||||
" text-align: right;\n",
|
|
||||||
" }\n",
|
|
||||||
"</style>\n",
|
|
||||||
"<table border=\"1\" class=\"dataframe\">\n",
|
|
||||||
" <thead>\n",
|
|
||||||
" <tr style=\"text-align: right;\">\n",
|
|
||||||
" <th></th>\n",
|
|
||||||
" <th>Name</th>\n",
|
|
||||||
" <th>Vorname</th>\n",
|
|
||||||
" </tr>\n",
|
|
||||||
" </thead>\n",
|
|
||||||
" <tbody>\n",
|
|
||||||
" <tr>\n",
|
|
||||||
" <th>0</th>\n",
|
|
||||||
" <td>Smith</td>\n",
|
|
||||||
" <td>John</td>\n",
|
|
||||||
" </tr>\n",
|
|
||||||
" <tr>\n",
|
|
||||||
" <th>1</th>\n",
|
|
||||||
" <td>Johnson</td>\n",
|
|
||||||
" <td>James</td>\n",
|
|
||||||
" </tr>\n",
|
|
||||||
" <tr>\n",
|
|
||||||
" <th>2</th>\n",
|
|
||||||
" <td>Williams</td>\n",
|
|
||||||
" <td>William</td>\n",
|
|
||||||
" </tr>\n",
|
|
||||||
" <tr>\n",
|
|
||||||
" <th>3</th>\n",
|
|
||||||
" <td>Brown</td>\n",
|
|
||||||
" <td>Michael</td>\n",
|
|
||||||
" </tr>\n",
|
|
||||||
" <tr>\n",
|
|
||||||
" <th>4</th>\n",
|
|
||||||
" <td>Davis</td>\n",
|
|
||||||
" <td>David</td>\n",
|
|
||||||
" </tr>\n",
|
|
||||||
" </tbody>\n",
|
|
||||||
"</table>\n",
|
|
||||||
"</div>"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
" Name Vorname\n",
|
|
||||||
"0 Smith John\n",
|
|
||||||
"1 Johnson James\n",
|
|
||||||
"2 Williams William\n",
|
|
||||||
"3 Brown Michael\n",
|
|
||||||
"4 Davis David"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 3,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"import pandas as pd\n",
|
|
||||||
"air = pd.read_csv(\"regie_name.csv\", nrows=5)\n",
|
|
||||||
"air"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 7,
|
|
||||||
"id": "8017742d-3b8e-4847-b5a3-4f28e0c9057a",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"Name\n",
|
|
||||||
"Flores 10.0\n",
|
|
||||||
"Davis 10.0\n",
|
|
||||||
"Gonzalez 10.0\n",
|
|
||||||
"Garcia 10.0\n",
|
|
||||||
"Cruz 10.0\n",
|
|
||||||
" ... \n",
|
|
||||||
"Taylor 1.0\n",
|
|
||||||
"White 1.0\n",
|
|
||||||
"Thompson 1.0\n",
|
|
||||||
"Wilson 1.0\n",
|
|
||||||
"Williams 1.0\n",
|
|
||||||
"Length: 47, dtype: float64\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"chunker = pd.read_csv(\"regie_name.csv\", chunksize=1000)\n",
|
|
||||||
"tot = pd.Series([], dtype='int64')\n",
|
|
||||||
"for piece in chunker:\n",
|
|
||||||
" tot = tot.add(piece[\"Name\"].value_counts(), fill_value=0)\n",
|
|
||||||
"tot = tot.sort_values(ascending=False)\n",
|
|
||||||
"print(tot)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"id": "d7531f34-19a6-4606-88f2-1c4fdd3b0b7d",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3 (ipykernel)",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.13.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 5
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
[defaults]
|
[defaults]
|
||||||
#inventory = /home/user06/hosts
|
#inventory = /home/user06/hosts
|
||||||
inventory = ./ansible_inv_main.py
|
inventory = ./ansible_inv_main.py
|
||||||
ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S on {host}
|
|
||||||
private_key_file = /home/jonnybravo/.ssh/ansible-test
|
private_key_file = /home/jonnybravo/.ssh/ansible-test
|
||||||
gathering = smart
|
gathering = smart
|
||||||
fact_caching = yaml
|
fact_caching = yaml
|
||||||
|
|||||||
@@ -44,7 +44,11 @@ def scan_csv(csvfile=str, colm="hostname"):
|
|||||||
with open(csvfile) as csv_file:
|
with open(csvfile) as csv_file:
|
||||||
csv_reader = csv.DictReader(csv_file, delimiter=",")
|
csv_reader = csv.DictReader(csv_file, delimiter=",")
|
||||||
for count, row in enumerate(csv_reader, 1):
|
for count, row in enumerate(csv_reader, 1):
|
||||||
hostlist.append(row[colm])
|
hostname = row[colm]
|
||||||
|
if port_open(address=hostname):
|
||||||
|
hostlist.append(hostname)
|
||||||
|
else:
|
||||||
|
print(f"INFO: Host {hostname} not reachable.", file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
raise FileNotFoundError(
|
raise FileNotFoundError(
|
||||||
errno.ENOENT, os.strerror(errno.ENOENT), csvfile)
|
errno.ENOENT, os.strerror(errno.ENOENT), csvfile)
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
|||||||
|
{"event": "verbose", "uuid": "b95d21e9-b710-47f0-aebe-b4e5368347b5", "counter": 1, "stdout": "\u001b[1;35m[WARNING]: No inventory was parsed, only implicit localhost is available\u001b[0m", "start_line": 0, "end_line": 1, "runner_ident": "58e17dd4-e88d-4c34-a94a-23bd985b69b4", "created": "2025-08-29T14:58:00.928440+00:00"}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "f337836a-fd03-4235-a519-a32ce2c8fba1", "counter": 10, "stdout": "\u001b[0;32mok: [localhost] => {\u001b[0m\r\n\u001b[0;32m \"msg\": \"Hello Ansible World\"\u001b[0m\r\n\u001b[0;32m}\u001b[0m", "start_line": 9, "end_line": 12, "runner_ident": "58e17dd4-e88d-4c34-a94a-23bd985b69b4", "event": "runner_on_ok", "pid": 902557, "created": "2025-08-29T14:58:02.503113+00:00", "parent_uuid": "c403a83c-0a7d-0892-b38a-000000000003", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-0892-b38a-000000000001", "play_pattern": "localhost", "task": "Print message", "task_uuid": "c403a83c-0a7d-0892-b38a-000000000003", "task_action": "debug", "resolved_action": "ansible.builtin.debug", "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:6", "host": "localhost", "remote_addr": "127.0.0.1", "res": {"msg": "Hello Ansible World", "_ansible_verbose_always": true, "changed": false, "_ansible_no_log": false}, "start": "2025-08-29T14:58:02.494227+00:00", "end": "2025-08-29T14:58:02.502915+00:00", "duration": 0.008688, "event_loop": null, "uuid": "f337836a-fd03-4235-a519-a32ce2c8fba1"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c2e28e9e-2cda-4522-9835-7504bd265a3c", "counter": 11, "stdout": "\r\nPLAY RECAP *********************************************************************\r\n\u001b[0;32mlocalhost\u001b[0m : \u001b[0;32mok=2 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ", "start_line": 12, "end_line": 16, "runner_ident": "58e17dd4-e88d-4c34-a94a-23bd985b69b4", "event": "playbook_on_stats", "pid": 902557, "created": "2025-08-29T14:58:02.504219+00:00", "parent_uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932", "changed": {}, "dark": {}, "failures": {}, "ignored": {}, "ok": {"localhost": 2}, "processed": {"localhost": 1}, "rescued": {}, "skipped": {}, "artifact_data": {}, "uuid": "c2e28e9e-2cda-4522-9835-7504bd265a3c"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"event": "verbose", "uuid": "ea718f2d-28ab-442f-8c62-75647a8ed9b4", "counter": 2, "stdout": "\u001b[1;35m[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'\u001b[0m", "start_line": 1, "end_line": 2, "runner_ident": "58e17dd4-e88d-4c34-a94a-23bd985b69b4", "created": "2025-08-29T14:58:00.932101+00:00"}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932", "counter": 3, "stdout": "", "start_line": 2, "end_line": 2, "runner_ident": "58e17dd4-e88d-4c34-a94a-23bd985b69b4", "event": "playbook_on_start", "pid": 902557, "created": "2025-08-29T14:58:00.985958+00:00", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932", "uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c403a83c-0a7d-0892-b38a-000000000001", "counter": 4, "stdout": "\r\nPLAY [Simple playbook] *********************************************************", "start_line": 2, "end_line": 4, "runner_ident": "58e17dd4-e88d-4c34-a94a-23bd985b69b4", "event": "playbook_on_play_start", "pid": 902557, "created": "2025-08-29T14:58:00.987257+00:00", "parent_uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-0892-b38a-000000000001", "play_pattern": "localhost", "name": "Simple playbook", "pattern": "localhost", "uuid": "c403a83c-0a7d-0892-b38a-000000000001"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c403a83c-0a7d-0892-b38a-000000000008", "counter": 5, "stdout": "\r\nTASK [Gathering Facts] *********************************************************", "start_line": 4, "end_line": 6, "runner_ident": "58e17dd4-e88d-4c34-a94a-23bd985b69b4", "event": "playbook_on_task_start", "pid": 902557, "created": "2025-08-29T14:58:00.991864+00:00", "parent_uuid": "c403a83c-0a7d-0892-b38a-000000000001", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-0892-b38a-000000000001", "play_pattern": "localhost", "task": "Gathering Facts", "task_uuid": "c403a83c-0a7d-0892-b38a-000000000008", "task_action": "gather_facts", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:2", "name": "Gathering Facts", "is_conditional": false, "uuid": "c403a83c-0a7d-0892-b38a-000000000008"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "85e3ef2e-d0a2-4736-a945-eed111e6bac7", "counter": 6, "stdout": "", "start_line": 6, "end_line": 6, "runner_ident": "58e17dd4-e88d-4c34-a94a-23bd985b69b4", "event": "runner_on_start", "pid": 902557, "created": "2025-08-29T14:58:00.992322+00:00", "parent_uuid": "c403a83c-0a7d-0892-b38a-000000000008", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-0892-b38a-000000000001", "play_pattern": "localhost", "task": "Gathering Facts", "task_uuid": "c403a83c-0a7d-0892-b38a-000000000008", "task_action": "gather_facts", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:2", "host": "localhost", "uuid": "85e3ef2e-d0a2-4736-a945-eed111e6bac7"}}
|
||||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c403a83c-0a7d-0892-b38a-000000000003", "counter": 8, "stdout": "\r\nTASK [Print message] ***********************************************************", "start_line": 7, "end_line": 9, "runner_ident": "58e17dd4-e88d-4c34-a94a-23bd985b69b4", "event": "playbook_on_task_start", "pid": 902557, "created": "2025-08-29T14:58:02.493698+00:00", "parent_uuid": "c403a83c-0a7d-0892-b38a-000000000001", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-0892-b38a-000000000001", "play_pattern": "localhost", "task": "Print message", "task_uuid": "c403a83c-0a7d-0892-b38a-000000000003", "task_action": "debug", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:6", "name": "Print message", "is_conditional": false, "uuid": "c403a83c-0a7d-0892-b38a-000000000003"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "52e95112-c3d4-4aad-92a1-593af4b67c14", "counter": 9, "stdout": "", "start_line": 9, "end_line": 9, "runner_ident": "58e17dd4-e88d-4c34-a94a-23bd985b69b4", "event": "runner_on_start", "pid": 902557, "created": "2025-08-29T14:58:02.494275+00:00", "parent_uuid": "c403a83c-0a7d-0892-b38a-000000000003", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "3ba9434a-1057-46bc-8e9d-908ca73dd932", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-0892-b38a-000000000001", "play_pattern": "localhost", "task": "Print message", "task_uuid": "c403a83c-0a7d-0892-b38a-000000000003", "task_action": "debug", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:6", "host": "localhost", "uuid": "52e95112-c3d4-4aad-92a1-593af4b67c14"}}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
0
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
successful
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[1;35m[WARNING]: No inventory was parsed, only implicit localhost is available[0m
|
||||||
|
[1;35m[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'[0m
|
||||||
|
|
||||||
|
PLAY [Simple playbook] *********************************************************
|
||||||
|
|
||||||
|
TASK [Gathering Facts] *********************************************************
|
||||||
|
[0;32mok: [localhost][0m
|
||||||
|
|
||||||
|
TASK [Print message] ***********************************************************
|
||||||
|
[0;32mok: [localhost] => {[0m
|
||||||
|
[0;32m "msg": "Hello Ansible World"[0m
|
||||||
|
[0;32m}[0m
|
||||||
|
|
||||||
|
PLAY RECAP *********************************************************************
|
||||||
|
[0;32mlocalhost[0m : [0;32mok=2 [0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
|
||||||
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
|||||||
|
{"event": "verbose", "uuid": "1cb860c3-420b-4605-97f1-2848d696677e", "counter": 1, "stdout": "\u001b[1;35m[WARNING]: No inventory was parsed, only implicit localhost is available\u001b[0m", "start_line": 0, "end_line": 1, "runner_ident": "593bddbd-810b-4e74-88dc-0cd7c9cdd6b9", "created": "2025-08-29T15:00:26.442517+00:00"}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "4b1be9b2-1bb7-4043-9a31-4891fec9fdb7", "counter": 10, "stdout": "\u001b[0;32mok: [localhost] => {\u001b[0m\r\n\u001b[0;32m \"msg\": \"Hello Ansible World\"\u001b[0m\r\n\u001b[0;32m}\u001b[0m", "start_line": 9, "end_line": 12, "runner_ident": "593bddbd-810b-4e74-88dc-0cd7c9cdd6b9", "event": "runner_on_ok", "pid": 903202, "created": "2025-08-29T15:00:27.953243+00:00", "parent_uuid": "c403a83c-0a7d-c752-d28b-000000000003", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-c752-d28b-000000000001", "play_pattern": "localhost", "task": "Print message", "task_uuid": "c403a83c-0a7d-c752-d28b-000000000003", "task_action": "debug", "resolved_action": "ansible.builtin.debug", "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:6", "host": "localhost", "remote_addr": "127.0.0.1", "res": {"msg": "Hello Ansible World", "_ansible_verbose_always": true, "changed": false, "_ansible_no_log": false}, "start": "2025-08-29T15:00:27.944028+00:00", "end": "2025-08-29T15:00:27.953032+00:00", "duration": 0.009004, "event_loop": null, "uuid": "4b1be9b2-1bb7-4043-9a31-4891fec9fdb7"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "b42a3b6b-b91b-43c9-ba52-439eb6939ca1", "counter": 11, "stdout": "\r\nPLAY RECAP *********************************************************************\r\n\u001b[0;32mlocalhost\u001b[0m : \u001b[0;32mok=2 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ", "start_line": 12, "end_line": 16, "runner_ident": "593bddbd-810b-4e74-88dc-0cd7c9cdd6b9", "event": "playbook_on_stats", "pid": 903202, "created": "2025-08-29T15:00:27.954620+00:00", "parent_uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89", "changed": {}, "dark": {}, "failures": {}, "ignored": {}, "ok": {"localhost": 2}, "processed": {"localhost": 1}, "rescued": {}, "skipped": {}, "artifact_data": {}, "uuid": "b42a3b6b-b91b-43c9-ba52-439eb6939ca1"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"event": "verbose", "uuid": "581f3687-da78-4de6-a346-01670cc6d1ac", "counter": 2, "stdout": "\u001b[1;35m[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'\u001b[0m", "start_line": 1, "end_line": 2, "runner_ident": "593bddbd-810b-4e74-88dc-0cd7c9cdd6b9", "created": "2025-08-29T15:00:26.446145+00:00"}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89", "counter": 3, "stdout": "", "start_line": 2, "end_line": 2, "runner_ident": "593bddbd-810b-4e74-88dc-0cd7c9cdd6b9", "event": "playbook_on_start", "pid": 903202, "created": "2025-08-29T15:00:26.501020+00:00", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89", "uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c403a83c-0a7d-c752-d28b-000000000001", "counter": 4, "stdout": "\r\nPLAY [Simple playbook] *********************************************************", "start_line": 2, "end_line": 4, "runner_ident": "593bddbd-810b-4e74-88dc-0cd7c9cdd6b9", "event": "playbook_on_play_start", "pid": 903202, "created": "2025-08-29T15:00:26.502556+00:00", "parent_uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-c752-d28b-000000000001", "play_pattern": "localhost", "name": "Simple playbook", "pattern": "localhost", "uuid": "c403a83c-0a7d-c752-d28b-000000000001"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c403a83c-0a7d-c752-d28b-000000000008", "counter": 5, "stdout": "\r\nTASK [Gathering Facts] *********************************************************", "start_line": 4, "end_line": 6, "runner_ident": "593bddbd-810b-4e74-88dc-0cd7c9cdd6b9", "event": "playbook_on_task_start", "pid": 903202, "created": "2025-08-29T15:00:26.508043+00:00", "parent_uuid": "c403a83c-0a7d-c752-d28b-000000000001", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-c752-d28b-000000000001", "play_pattern": "localhost", "task": "Gathering Facts", "task_uuid": "c403a83c-0a7d-c752-d28b-000000000008", "task_action": "gather_facts", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:2", "name": "Gathering Facts", "is_conditional": false, "uuid": "c403a83c-0a7d-c752-d28b-000000000008"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "65252c48-7cf3-47e6-b791-ceeb40f3d376", "counter": 6, "stdout": "", "start_line": 6, "end_line": 6, "runner_ident": "593bddbd-810b-4e74-88dc-0cd7c9cdd6b9", "event": "runner_on_start", "pid": 903202, "created": "2025-08-29T15:00:26.508649+00:00", "parent_uuid": "c403a83c-0a7d-c752-d28b-000000000008", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-c752-d28b-000000000001", "play_pattern": "localhost", "task": "Gathering Facts", "task_uuid": "c403a83c-0a7d-c752-d28b-000000000008", "task_action": "gather_facts", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:2", "host": "localhost", "uuid": "65252c48-7cf3-47e6-b791-ceeb40f3d376"}}
|
||||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c403a83c-0a7d-c752-d28b-000000000003", "counter": 8, "stdout": "\r\nTASK [Print message] ***********************************************************", "start_line": 7, "end_line": 9, "runner_ident": "593bddbd-810b-4e74-88dc-0cd7c9cdd6b9", "event": "playbook_on_task_start", "pid": 903202, "created": "2025-08-29T15:00:27.943544+00:00", "parent_uuid": "c403a83c-0a7d-c752-d28b-000000000001", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-c752-d28b-000000000001", "play_pattern": "localhost", "task": "Print message", "task_uuid": "c403a83c-0a7d-c752-d28b-000000000003", "task_action": "debug", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:6", "name": "Print message", "is_conditional": false, "uuid": "c403a83c-0a7d-c752-d28b-000000000003"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "131837f4-0404-468f-b1e2-269a3feafbce", "counter": 9, "stdout": "", "start_line": 9, "end_line": 9, "runner_ident": "593bddbd-810b-4e74-88dc-0cd7c9cdd6b9", "event": "runner_on_start", "pid": 903202, "created": "2025-08-29T15:00:27.944071+00:00", "parent_uuid": "c403a83c-0a7d-c752-d28b-000000000003", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "02eef34c-064c-4e67-a88c-02bfa5c8eb89", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-c752-d28b-000000000001", "play_pattern": "localhost", "task": "Print message", "task_uuid": "c403a83c-0a7d-c752-d28b-000000000003", "task_action": "debug", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:6", "host": "localhost", "uuid": "131837f4-0404-468f-b1e2-269a3feafbce"}}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
0
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
successful
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[1;35m[WARNING]: No inventory was parsed, only implicit localhost is available[0m
|
||||||
|
[1;35m[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'[0m
|
||||||
|
|
||||||
|
PLAY [Simple playbook] *********************************************************
|
||||||
|
|
||||||
|
TASK [Gathering Facts] *********************************************************
|
||||||
|
[0;32mok: [localhost][0m
|
||||||
|
|
||||||
|
TASK [Print message] ***********************************************************
|
||||||
|
[0;32mok: [localhost] => {[0m
|
||||||
|
[0;32m "msg": "Hello Ansible World"[0m
|
||||||
|
[0;32m}[0m
|
||||||
|
|
||||||
|
PLAY RECAP *********************************************************************
|
||||||
|
[0;32mlocalhost[0m : [0;32mok=2 [0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
|
||||||
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
|||||||
|
{"event": "verbose", "uuid": "ad6f46a1-dab9-4683-9083-ddd461acb8ba", "counter": 1, "stdout": "\u001b[1;35m[WARNING]: No inventory was parsed, only implicit localhost is available\u001b[0m", "start_line": 0, "end_line": 1, "runner_ident": "cecc2a8d-546f-48e0-acd9-4c3d36c73994", "created": "2025-08-29T13:47:48.946761+00:00"}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "7d3ddbba-7e61-4dcd-b5ea-177985863b14", "counter": 10, "stdout": "\u001b[0;32mok: [localhost] => {\u001b[0m\r\n\u001b[0;32m \"msg\": \"Hello Ansible World\"\u001b[0m\r\n\u001b[0;32m}\u001b[0m", "start_line": 9, "end_line": 12, "runner_ident": "cecc2a8d-546f-48e0-acd9-4c3d36c73994", "event": "runner_on_ok", "pid": 898221, "created": "2025-08-29T13:47:50.458632+00:00", "parent_uuid": "c403a83c-0a7d-9960-2310-000000000003", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-9960-2310-000000000001", "play_pattern": "localhost", "task": "Print message", "task_uuid": "c403a83c-0a7d-9960-2310-000000000003", "task_action": "debug", "resolved_action": "ansible.builtin.debug", "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:6", "host": "localhost", "remote_addr": "127.0.0.1", "res": {"msg": "Hello Ansible World", "_ansible_verbose_always": true, "changed": false, "_ansible_no_log": false}, "start": "2025-08-29T13:47:50.449895+00:00", "end": "2025-08-29T13:47:50.458374+00:00", "duration": 0.008479, "event_loop": null, "uuid": "7d3ddbba-7e61-4dcd-b5ea-177985863b14"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "62d02f82-08db-492c-9483-8d93358a05be", "counter": 11, "stdout": "\r\nPLAY RECAP *********************************************************************\r\n\u001b[0;32mlocalhost\u001b[0m : \u001b[0;32mok=2 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ", "start_line": 12, "end_line": 16, "runner_ident": "cecc2a8d-546f-48e0-acd9-4c3d36c73994", "event": "playbook_on_stats", "pid": 898221, "created": "2025-08-29T13:47:50.459807+00:00", "parent_uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078", "changed": {}, "dark": {}, "failures": {}, "ignored": {}, "ok": {"localhost": 2}, "processed": {"localhost": 1}, "rescued": {}, "skipped": {}, "artifact_data": {}, "uuid": "62d02f82-08db-492c-9483-8d93358a05be"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"event": "verbose", "uuid": "99ea232e-0942-4238-8bd2-505ee5c9e351", "counter": 2, "stdout": "\u001b[1;35m[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'\u001b[0m", "start_line": 1, "end_line": 2, "runner_ident": "cecc2a8d-546f-48e0-acd9-4c3d36c73994", "created": "2025-08-29T13:47:48.950812+00:00"}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078", "counter": 3, "stdout": "", "start_line": 2, "end_line": 2, "runner_ident": "cecc2a8d-546f-48e0-acd9-4c3d36c73994", "event": "playbook_on_start", "pid": 898221, "created": "2025-08-29T13:47:49.013875+00:00", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078", "uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c403a83c-0a7d-9960-2310-000000000001", "counter": 4, "stdout": "\r\nPLAY [Simple playbook] *********************************************************", "start_line": 2, "end_line": 4, "runner_ident": "cecc2a8d-546f-48e0-acd9-4c3d36c73994", "event": "playbook_on_play_start", "pid": 898221, "created": "2025-08-29T13:47:49.015282+00:00", "parent_uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-9960-2310-000000000001", "play_pattern": "localhost", "name": "Simple playbook", "pattern": "localhost", "uuid": "c403a83c-0a7d-9960-2310-000000000001"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c403a83c-0a7d-9960-2310-000000000008", "counter": 5, "stdout": "\r\nTASK [Gathering Facts] *********************************************************", "start_line": 4, "end_line": 6, "runner_ident": "cecc2a8d-546f-48e0-acd9-4c3d36c73994", "event": "playbook_on_task_start", "pid": 898221, "created": "2025-08-29T13:47:49.020611+00:00", "parent_uuid": "c403a83c-0a7d-9960-2310-000000000001", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-9960-2310-000000000001", "play_pattern": "localhost", "task": "Gathering Facts", "task_uuid": "c403a83c-0a7d-9960-2310-000000000008", "task_action": "gather_facts", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:2", "name": "Gathering Facts", "is_conditional": false, "uuid": "c403a83c-0a7d-9960-2310-000000000008"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "cfd400a6-69ce-4d3c-8e38-b75c0a9ffbfc", "counter": 6, "stdout": "", "start_line": 6, "end_line": 6, "runner_ident": "cecc2a8d-546f-48e0-acd9-4c3d36c73994", "event": "runner_on_start", "pid": 898221, "created": "2025-08-29T13:47:49.021050+00:00", "parent_uuid": "c403a83c-0a7d-9960-2310-000000000008", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-9960-2310-000000000001", "play_pattern": "localhost", "task": "Gathering Facts", "task_uuid": "c403a83c-0a7d-9960-2310-000000000008", "task_action": "gather_facts", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:2", "host": "localhost", "uuid": "cfd400a6-69ce-4d3c-8e38-b75c0a9ffbfc"}}
|
||||||
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c403a83c-0a7d-9960-2310-000000000003", "counter": 8, "stdout": "\r\nTASK [Print message] ***********************************************************", "start_line": 7, "end_line": 9, "runner_ident": "cecc2a8d-546f-48e0-acd9-4c3d36c73994", "event": "playbook_on_task_start", "pid": 898221, "created": "2025-08-29T13:47:50.449363+00:00", "parent_uuid": "c403a83c-0a7d-9960-2310-000000000001", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-9960-2310-000000000001", "play_pattern": "localhost", "task": "Print message", "task_uuid": "c403a83c-0a7d-9960-2310-000000000003", "task_action": "debug", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:6", "name": "Print message", "is_conditional": false, "uuid": "c403a83c-0a7d-9960-2310-000000000003"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "0f3383fe-bf86-410a-944d-8de2101092b7", "counter": 9, "stdout": "", "start_line": 9, "end_line": 9, "runner_ident": "cecc2a8d-546f-48e0-acd9-4c3d36c73994", "event": "runner_on_start", "pid": 898221, "created": "2025-08-29T13:47:50.449938+00:00", "parent_uuid": "c403a83c-0a7d-9960-2310-000000000003", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "99a98f6a-089c-42d6-a19e-ed425ba92078", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-9960-2310-000000000001", "play_pattern": "localhost", "task": "Print message", "task_uuid": "c403a83c-0a7d-9960-2310-000000000003", "task_action": "debug", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:6", "host": "localhost", "uuid": "0f3383fe-bf86-410a-944d-8de2101092b7"}}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
0
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
successful
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[1;35m[WARNING]: No inventory was parsed, only implicit localhost is available[0m
|
||||||
|
[1;35m[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'[0m
|
||||||
|
|
||||||
|
PLAY [Simple playbook] *********************************************************
|
||||||
|
|
||||||
|
TASK [Gathering Facts] *********************************************************
|
||||||
|
[0;32mok: [localhost][0m
|
||||||
|
|
||||||
|
TASK [Print message] ***********************************************************
|
||||||
|
[0;32mok: [localhost] => {[0m
|
||||||
|
[0;32m "msg": "Hello Ansible World"[0m
|
||||||
|
[0;32m}[0m
|
||||||
|
|
||||||
|
PLAY RECAP *********************************************************************
|
||||||
|
[0;32mlocalhost[0m : [0;32mok=2 [0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
|
||||||
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+1
@@ -0,0 +1 @@
|
|||||||
|
{"event": "verbose", "uuid": "77db1dac-c490-443d-9989-4d28a08eb31c", "counter": 1, "stdout": "\u001b[1;35m[WARNING]: No inventory was parsed, only implicit localhost is available\u001b[0m", "start_line": 0, "end_line": 1, "runner_ident": "d5fdc75b-c25d-418f-982d-3a0872a2792f", "created": "2025-08-29T13:50:22.957726+00:00"}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "29708dd0-33ec-45da-85ba-527cf1954cf9", "counter": 10, "stdout": "\u001b[0;32mok: [localhost] => {\u001b[0m\r\n\u001b[0;32m \"msg\": \"Hello Ansible World\"\u001b[0m\r\n\u001b[0;32m}\u001b[0m", "start_line": 9, "end_line": 12, "runner_ident": "d5fdc75b-c25d-418f-982d-3a0872a2792f", "event": "runner_on_ok", "pid": 898727, "created": "2025-08-29T13:50:24.484808+00:00", "parent_uuid": "c403a83c-0a7d-9b7b-9dbc-000000000003", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "48db46ba-55d1-4954-8db6-37caef1fd04f", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-9b7b-9dbc-000000000001", "play_pattern": "localhost", "task": "Print message", "task_uuid": "c403a83c-0a7d-9b7b-9dbc-000000000003", "task_action": "debug", "resolved_action": "ansible.builtin.debug", "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:6", "host": "localhost", "remote_addr": "127.0.0.1", "res": {"msg": "Hello Ansible World", "_ansible_verbose_always": true, "changed": false, "_ansible_no_log": false}, "start": "2025-08-29T13:50:24.475492+00:00", "end": "2025-08-29T13:50:24.484539+00:00", "duration": 0.009047, "event_loop": null, "uuid": "29708dd0-33ec-45da-85ba-527cf1954cf9"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "9dd0d18a-9c0e-4015-a537-8a0bbb486522", "counter": 11, "stdout": "\r\nPLAY RECAP *********************************************************************\r\n\u001b[0;32mlocalhost\u001b[0m : \u001b[0;32mok=2 \u001b[0m changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 ", "start_line": 12, "end_line": 16, "runner_ident": "d5fdc75b-c25d-418f-982d-3a0872a2792f", "event": "playbook_on_stats", "pid": 898727, "created": "2025-08-29T13:50:24.486291+00:00", "parent_uuid": "48db46ba-55d1-4954-8db6-37caef1fd04f", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "48db46ba-55d1-4954-8db6-37caef1fd04f", "changed": {}, "dark": {}, "failures": {}, "ignored": {}, "ok": {"localhost": 2}, "processed": {"localhost": 1}, "rescued": {}, "skipped": {}, "artifact_data": {}, "uuid": "9dd0d18a-9c0e-4015-a537-8a0bbb486522"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"event": "verbose", "uuid": "7dcf913c-abbf-4d17-84bc-ba873247d4f3", "counter": 2, "stdout": "\u001b[1;35m[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'\u001b[0m", "start_line": 1, "end_line": 2, "runner_ident": "d5fdc75b-c25d-418f-982d-3a0872a2792f", "created": "2025-08-29T13:50:22.961598+00:00"}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "48db46ba-55d1-4954-8db6-37caef1fd04f", "counter": 3, "stdout": "", "start_line": 2, "end_line": 2, "runner_ident": "d5fdc75b-c25d-418f-982d-3a0872a2792f", "event": "playbook_on_start", "pid": 898727, "created": "2025-08-29T13:50:23.015512+00:00", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "48db46ba-55d1-4954-8db6-37caef1fd04f", "uuid": "48db46ba-55d1-4954-8db6-37caef1fd04f"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c403a83c-0a7d-9b7b-9dbc-000000000001", "counter": 4, "stdout": "\r\nPLAY [Simple playbook] *********************************************************", "start_line": 2, "end_line": 4, "runner_ident": "d5fdc75b-c25d-418f-982d-3a0872a2792f", "event": "playbook_on_play_start", "pid": 898727, "created": "2025-08-29T13:50:23.016831+00:00", "parent_uuid": "48db46ba-55d1-4954-8db6-37caef1fd04f", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "48db46ba-55d1-4954-8db6-37caef1fd04f", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-9b7b-9dbc-000000000001", "play_pattern": "localhost", "name": "Simple playbook", "pattern": "localhost", "uuid": "c403a83c-0a7d-9b7b-9dbc-000000000001"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "c403a83c-0a7d-9b7b-9dbc-000000000008", "counter": 5, "stdout": "\r\nTASK [Gathering Facts] *********************************************************", "start_line": 4, "end_line": 6, "runner_ident": "d5fdc75b-c25d-418f-982d-3a0872a2792f", "event": "playbook_on_task_start", "pid": 898727, "created": "2025-08-29T13:50:23.021982+00:00", "parent_uuid": "c403a83c-0a7d-9b7b-9dbc-000000000001", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "48db46ba-55d1-4954-8db6-37caef1fd04f", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-9b7b-9dbc-000000000001", "play_pattern": "localhost", "task": "Gathering Facts", "task_uuid": "c403a83c-0a7d-9b7b-9dbc-000000000008", "task_action": "gather_facts", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:2", "name": "Gathering Facts", "is_conditional": false, "uuid": "c403a83c-0a7d-9b7b-9dbc-000000000008"}}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"uuid": "f852c0c3-f1e2-4170-ad79-1447b59273a7", "counter": 6, "stdout": "", "start_line": 6, "end_line": 6, "runner_ident": "d5fdc75b-c25d-418f-982d-3a0872a2792f", "event": "runner_on_start", "pid": 898727, "created": "2025-08-29T13:50:23.022451+00:00", "parent_uuid": "c403a83c-0a7d-9b7b-9dbc-000000000008", "event_data": {"playbook": "playbook.yml", "playbook_uuid": "48db46ba-55d1-4954-8db6-37caef1fd04f", "play": "Simple playbook", "play_uuid": "c403a83c-0a7d-9b7b-9dbc-000000000001", "play_pattern": "localhost", "task": "Gathering Facts", "task_uuid": "c403a83c-0a7d-9b7b-9dbc-000000000008", "task_action": "gather_facts", "resolved_action": null, "task_args": "", "task_path": "/home/jonnybravo/Projekte/Python_Skripte/play_ansible/run_play/play/playbook.yml:2", "host": "localhost", "uuid": "f852c0c3-f1e2-4170-ad79-1447b59273a7"}}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user