Compare commits
11 Commits
c122d54979
...
master
Author | SHA1 | Date | |
---|---|---|---|
3cc07f2b86 | |||
c5c16c649a | |||
b1c553e015 | |||
b57c0117e4 | |||
4d7170f570 | |||
4766e87e8a | |||
4c24a87bc2 | |||
fe74632ae3 | |||
4ff22a54a4 | |||
df5f235129 | |||
7d9587b26d |
93
.gitea/workflows/publish.yml
Normal file
93
.gitea/workflows/publish.yml
Normal file
@ -0,0 +1,93 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
name: 🐍 Build & Publish Python Packages
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: 📦 Cloner le dépôt
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: 🔍 Sélectionner les projets à publier
|
||||
id: detect
|
||||
env:
|
||||
DEVPI_URL: ${{ vars.DEVPI_URL }}
|
||||
DEVPI_USERNAME: ${{ secrets.DEVPI_USERNAME }}
|
||||
run: |
|
||||
set +e # Ne pas interrompre le script en cas d'erreur
|
||||
git fetch origin master --depth=2 || true
|
||||
CHANGED=$(git diff --name-only HEAD~1 HEAD || echo "")
|
||||
|
||||
#echo "🔍 Fichiers modifiés: $CHANGED"
|
||||
|
||||
SELECTED=""
|
||||
for dir in */; do
|
||||
if [ ! -f "$dir/setup.py" ]; then
|
||||
echo "⏭️ $dir ignoré (pas de setup.py)"
|
||||
continue
|
||||
fi
|
||||
|
||||
NAME=$(cd "$dir" && python3 setup.py --name 2>/dev/null)
|
||||
if [ -z "$NAME" ]; then
|
||||
echo "⚠️ Aucun nom récupéré pour $dir"
|
||||
continue
|
||||
fi
|
||||
|
||||
VERSION=$(cd "$dir" && python3 setup.py --version 2>/dev/null)
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "⚠️ Aucune version récupéré pour $dir"
|
||||
continue
|
||||
fi
|
||||
|
||||
for f in $CHANGED; do
|
||||
if [[ "$f" == "$dir"* ]]; then
|
||||
echo "🟡 Modification détectée dans $dir"
|
||||
fi
|
||||
done
|
||||
|
||||
API_URL="https://$DEVPI_URL/$DEVPI_USERNAME/dev/$NAME/$VERSION"
|
||||
STATUS_CODE=$(curl -L -s -o /dev/null -w "%{http_code}" "$API_URL")
|
||||
|
||||
if [ "$STATUS_CODE" = "404" ]; then
|
||||
echo "📦 $NAME version $VERSION n'existe pas (HTTP $STATUS_CODE)"
|
||||
SELECTED+="$dir "
|
||||
else
|
||||
echo "🔄 $NAME version $VERSION déjà présente (HTTP $STATUS_CODE)"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "selected_projects=$SELECTED" >> $GITHUB_OUTPUT
|
||||
echo "✅ Projets sélectionnés: $SELECTED"
|
||||
|
||||
- name: 🔧 Installer les outils Python
|
||||
if: steps.detect.outputs.selected_projects != ''
|
||||
run: |
|
||||
python3 -m pip install --break-system-packages setuptools wheel twine
|
||||
|
||||
- name: 🚀 Publier les projets sélectionnés
|
||||
if: steps.detect.outputs.selected_projects != ''
|
||||
env:
|
||||
DEVPI_URL: ${{ vars.DEVPI_URL }}
|
||||
DEVPI_USERNAME: ${{ secrets.DEVPI_USERNAME }}
|
||||
DEVPI_PASSWORD: ${{ secrets.DEVPI_PASSWORD }}
|
||||
run: |
|
||||
for dir in ${{ steps.detect.outputs.selected_projects }}; do
|
||||
echo "🚀 Publication de $dir"
|
||||
cd "$dir"
|
||||
python3 setup.py sdist
|
||||
twine upload \
|
||||
--repository-url https://$DEVPI_URL/$DEVPI_USERNAME/dev \
|
||||
-u "$DEVPI_USERNAME" \
|
||||
-p "$DEVPI_PASSWORD" \
|
||||
dist/* || exit 1
|
||||
cd -
|
||||
done
|
||||
|
||||
- name: ✅ Aucun projet à publier
|
||||
if: steps.detect.outputs.selected_projects == ''
|
||||
run: echo "✅ Aucun projet modifié ou nouveau. Rien à publier."
|
@ -1,7 +1,7 @@
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='HandBrake_recursive',
|
||||
name='HandBrake-recursive',
|
||||
version='0.1.0',
|
||||
description='Un script pour traiter les fichiers vidéo avec HandBrake de manière récursive.',
|
||||
py_modules=['HandBrake_recursive'],
|
||||
|
28
README.md
28
README.md
@ -2,6 +2,8 @@
|
||||
|
||||
Ce dépôt contient plusieurs projets Python que vous pouvez installer et utiliser avec `pipx`.
|
||||
|
||||
Dépôt PyPi → [🔗 devpi.netdldata.net](https://devpi.netdldata.net/lionel/dev)
|
||||
|
||||
## Installation de pipx
|
||||
|
||||
Si `pipx` n'est pas installé, vous pouvez l'installer en utilisant les commandes suivantes selon votre distribution :
|
||||
@ -35,9 +37,7 @@ pipx ensurepath
|
||||
Un outil pour encoder des vidéos de manière récursive en utilisant HandBrake. Il permet de traiter des fichiers vidéo dans un répertoire donné, en utilisant des presets définis pour le transcodage. Il génère également un résumé des opérations effectuées dans un fichier Excel.
|
||||
|
||||
```bash
|
||||
git clone https://git.netdldata.net/lionel/ProjetsPython.git
|
||||
cd ProjetsPython/HandBrake_recursive
|
||||
pipx install .
|
||||
pipx install --index-url https://devpi.netdldata.net/lionel/dev/+simple HandBrake-recursive
|
||||
```
|
||||
|
||||
### proxmox_export_disk
|
||||
@ -45,9 +45,7 @@ pipx install .
|
||||
Un script pour exporter des informations sur les disques depuis Proxmox. Il récupère les détails des disques des machines virtuelles et des conteneurs sur un serveur Proxmox, et exporte ces informations dans un fichier Excel ou ODS.
|
||||
|
||||
```bash
|
||||
git clone https://git.netdldata.net/lionel/ProjetsPython.git
|
||||
cd ProjetsPython/proxmox_export_disk
|
||||
pipx install .
|
||||
pipx install --index-url https://devpi.netdldata.net/lionel/dev/+simple proxmox-export-disk
|
||||
```
|
||||
|
||||
### tree_stream
|
||||
@ -55,9 +53,7 @@ pipx install .
|
||||
Un utilitaire pour afficher la structure des répertoires sous forme de flux. Il permet de visualiser l'arborescence des fichiers et des dossiers avec des informations supplémentaires sur les fichiers vidéo, comme les flux et les chapitres.
|
||||
|
||||
```bash
|
||||
git clone https://git.netdldata.net/lionel/ProjetsPython.git
|
||||
cd ProjetsPython/tree_stream
|
||||
pipx install .
|
||||
pipx install --index-url https://devpi.netdldata.net/lionel/dev/+simple tree-stream
|
||||
```
|
||||
|
||||
### multiplex
|
||||
@ -66,17 +62,5 @@ Un script Python pour assembler des pistes vidéo, audio et sous-titres issues d
|
||||
Il gère la priorité des pistes françaises, la définition des pistes par défaut, la gestion des chapitres et le renommage intelligent des pistes.
|
||||
|
||||
```bash
|
||||
git clone https://git.netdldata.net/lionel/ProjetsPython.git
|
||||
cd ProjetsPython/multiplex
|
||||
pipx install .
|
||||
```
|
||||
|
||||
### Installer tous les projets
|
||||
|
||||
```bash
|
||||
git clone https://git.netdldata.net/lionel/ProjetsPython.git
|
||||
cd ProjetsPython
|
||||
for dir in */; do
|
||||
(cd "$dir" && pipx install .)
|
||||
done
|
||||
pipx install --index-url https://devpi.netdldata.net/lionel/dev/+simple multiplex
|
||||
```
|
||||
|
3
multiplex/.gitignore
vendored
Normal file
3
multiplex/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
build
|
||||
multiplex.egg-info
|
||||
.venv
|
@ -2,6 +2,7 @@ import os
|
||||
import sys
|
||||
import glob
|
||||
import re
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from pymkv import MKVFile, MKVTrack
|
||||
|
||||
@ -50,9 +51,13 @@ def find_episode_file(source_dir, saison, episode):
|
||||
:param episode: Numéro de l'épisode
|
||||
:return: Chemin du fichier trouvé ou None
|
||||
"""
|
||||
target = f"s0{saison}e{episode}".lower()
|
||||
for file in glob.glob(os.path.join(source_dir, "*.mkv")):
|
||||
if target in os.path.basename(file).lower():
|
||||
pattern = re.compile(rf"s{int(saison):02d}\s*[ex]{int(episode):02d}", re.IGNORECASE)
|
||||
p = Path(source_dir)
|
||||
# On récupère tous les fichiers mkv ou mp4 en une seule liste
|
||||
files = list(p.glob("*.mkv")) + list(p.glob("*.mp4"))
|
||||
|
||||
for file in files:
|
||||
if pattern.search(os.path.basename(file)):
|
||||
return file
|
||||
return None
|
||||
|
||||
@ -68,15 +73,7 @@ def find_first_video_track_index(mkv_file):
|
||||
return idx
|
||||
return None
|
||||
|
||||
def has_named_chapters(chapters):
|
||||
"""
|
||||
Détermine si une liste de chapitres contient des noms réels (autres que des génériques).
|
||||
"""
|
||||
import re
|
||||
pattern = re.compile(r'(?i)^\s*(chapter|chapitre)\s*\d+\s*$')
|
||||
return any(not pattern.match(c.name or '') for c in chapters)
|
||||
|
||||
def process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, dest_dir):
|
||||
def process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, dest_dir, chapitre):
|
||||
"""
|
||||
Traite un épisode en combinant les pistes vidéo et audio/sous-titres de deux sources.
|
||||
|
||||
@ -86,6 +83,7 @@ def process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, des
|
||||
:param saison: Numéro de saison
|
||||
:param serie_name: Nom de la série
|
||||
:param dest_dir: Répertoire de sortie
|
||||
:param chapitre: Indique quels chapitres inclure dans le fichier final
|
||||
:return: None
|
||||
"""
|
||||
# Affiche une ligne bleue pour la lisibilité dans le terminal
|
||||
@ -145,7 +143,7 @@ def process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, des
|
||||
subtitle_tracks_other = [t for t in source_2_mkv.tracks if t.track_type == 'subtitles' and t.language != 'fre']
|
||||
|
||||
for idx, track in enumerate(subtitle_tracks_fr):
|
||||
track.default_track = (idx == 0)
|
||||
track.default_track = (idx == 0) and track.default_track
|
||||
if not track.track_name:
|
||||
codec = track._track_codec
|
||||
if track.forced_track:
|
||||
@ -163,27 +161,14 @@ def process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, des
|
||||
final_mkv.add_track(track)
|
||||
|
||||
# Traitement des chapitres
|
||||
try:
|
||||
chapters_1 = (source_1_mkv._info_json.get('chapters'))[0].get('num_entries')
|
||||
except (AttributeError, IndexError):
|
||||
chapters_1 = 0
|
||||
try:
|
||||
chapters_2 = (source_2_mkv._info_json.get('chapters'))[0].get('num_entries')
|
||||
except (AttributeError, IndexError):
|
||||
chapters_2 = 0
|
||||
|
||||
valid_1 = chapters_1 >= 4
|
||||
valid_2 = chapters_2 >= 4
|
||||
|
||||
if valid_1 and len(chapters_1) >= len(chapters_2):
|
||||
if chapitre in ('v', 'video'):
|
||||
source_2_mkv.no_chapters()
|
||||
elif valid_2:
|
||||
elif chapitre in ('a', 'audio'):
|
||||
source_1_mkv.no_chapters()
|
||||
else:
|
||||
source_1_mkv.no_chapters()
|
||||
source_2_mkv.no_chapters()
|
||||
|
||||
|
||||
# Éffacer tous les tags
|
||||
source_1_mkv.no_global_tags()
|
||||
source_2_mkv.no_global_tags()
|
||||
@ -201,26 +186,57 @@ def process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, des
|
||||
|
||||
def main():
|
||||
"""
|
||||
Point d'entrée principal du script.
|
||||
|
||||
Lit les arguments de ligne de commande, prépare les répertoires,
|
||||
et lance le traitement de chaque épisode (de 01 à 30).
|
||||
@brief Point d'entrée du script.
|
||||
@details Parse les arguments en ligne de commande et lance le traitement
|
||||
des épisodes de la série.
|
||||
@arg -v, --video Répertoire source vidéo
|
||||
@arg -a, --audio Répertoire source audio/sous-titres
|
||||
@arg -va Répertoire source commun pour vidéo et audio
|
||||
@arg -n, --nom Nom de la série
|
||||
@arg -s, --saison Numéro de la saison
|
||||
@arg -d, --dest Répertoire de sortie
|
||||
@return None
|
||||
"""
|
||||
if len(sys.argv) != 5:
|
||||
print(f'Usage: {sys.argv[0]} <SOURCE_DIR_1> <SOURCE_DIR_2> <SERIE_NAME> <SAISON>')
|
||||
sys.exit(1)
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Combine des épisodes MKV depuis deux sources (vidéo + audio/sous-titres)."
|
||||
)
|
||||
|
||||
source_dir_1 = sys.argv[1]
|
||||
source_dir_2 = sys.argv[2]
|
||||
serie_name = sys.argv[3]
|
||||
saison = sys.argv[4]
|
||||
dest_dir = f"/media/data/reencoded/{serie_name}/Saison {saison}"
|
||||
parser.add_argument("-v", "--video", help="Répertoire source vidéo" )
|
||||
parser.add_argument("-a", "--audio", help="Répertoire source audio/sous-titres" )
|
||||
parser.add_argument("-va", help="Répertoire source commun pour vidéo et audio" )
|
||||
parser.add_argument("-n", "--nom", required=True, help="Nom de la série")
|
||||
parser.add_argument("-s", "--saison", required=True, help="Numéro de la saison")
|
||||
parser.add_argument("-d", "--dest", required=True, help="Répertoire de sortie")
|
||||
parser.add_argument("-c", "--chapitre", choices=['n', 'non', 'v', 'video', 'a', 'audio'], default='a', help="Gestion des chapitres : 'n'/'non' pour aucun, 'v'/'video' pour source vidéo, 'a'/'audio' pour source audio (par défaut 'a')")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Gestion de l'option commune -va
|
||||
if args.va:
|
||||
source_dir_1 = source_dir_2 = args.va
|
||||
else:
|
||||
source_dir_1 = args.video
|
||||
source_dir_2 = args.audio
|
||||
|
||||
# Vérification que les deux dossiers sont renseignés
|
||||
if not source_dir_1 or not source_dir_2:
|
||||
parser.error("Vous devez fournir soit -va, soit à la fois -v et -a.")
|
||||
|
||||
serie_name = args.nom
|
||||
saison = args.saison
|
||||
chapitre = args.chapitre
|
||||
|
||||
# Chemin de sortie
|
||||
dest_dir = f"{args.dest}/{serie_name}/Saison {saison}"
|
||||
Path(dest_dir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for i in range(1, 31):
|
||||
# Compte le nombre de fichiers dans chaque répertoire source
|
||||
count1 = sum(1 for _ in Path(source_dir_1).iterdir() if _.is_file())
|
||||
count2 = sum(1 for _ in Path(source_dir_2).iterdir() if _.is_file())
|
||||
|
||||
for i in range(1, max(count1, count2) + 1):
|
||||
episode = f"{i:02}"
|
||||
process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, dest_dir)
|
||||
process_episode(episode, source_dir_1, source_dir_2, saison, serie_name, dest_dir, chapitre)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -2,7 +2,7 @@ from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='multiplex',
|
||||
version='0.1.0',
|
||||
version='0.1.2',
|
||||
description='Un script pour multiplexer les fichiers vidéo avec mkvmerge.',
|
||||
py_modules=['multiplex'],
|
||||
install_requires=[
|
||||
|
@ -1,7 +1,7 @@
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='proxmox_export_disk',
|
||||
name='proxmox-export-disk',
|
||||
version='0.1.0',
|
||||
description='Un script pour récupérer l\'utilisation des disques des VMs dans Proxmox.',
|
||||
py_modules=['proxmox_export_disk'],
|
||||
|
@ -1,7 +1,7 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="tree_stream",
|
||||
name="tree-stream",
|
||||
version="0.1.0",
|
||||
description="Affiche une arborescence enrichie des fichiers vidéo avec chapitres et flux",
|
||||
author="TonNom",
|
||||
|
Reference in New Issue
Block a user