Give alias and random suffix for whatsapp videos without created timestamp
This commit is contained in:
@@ -82,4 +82,9 @@ flowchart TB
|
||||
L_raw_pgrm1_0@{ animation: slow }
|
||||
L_pgrm1_videos_0@{ animation: slow }
|
||||
L_videos_playlists_0@{ animation: fast }
|
||||
```
|
||||
```
|
||||
|
||||
|
||||
# TODO
|
||||
|
||||
- [ ] Pouvoir supprimer une vidéo / regénérer une vidéo
|
||||
@@ -77,6 +77,11 @@ def update_video_difficulty(file_name, level):
|
||||
conn.execute("UPDATE videos SET difficulty_level = ? WHERE file_name = ?", (level, file_name))
|
||||
conn.commit()
|
||||
|
||||
def update_video_alias(file_name, alias):
|
||||
with get_conn() as conn:
|
||||
conn.execute("UPDATE videos SET alias = ? WHERE file_name = ?", (alias, file_name))
|
||||
conn.commit()
|
||||
|
||||
def get_unique_days():
|
||||
"""Retourne la liste unique des jours de la semaine enregistrés dans la base."""
|
||||
with get_conn() as conn:
|
||||
|
||||
@@ -18,6 +18,7 @@ class Video(BaseModel):
|
||||
long: Optional[float] = None
|
||||
address: Optional[str] = None
|
||||
difficulty_level: Optional[str] = Field("Tout niveau", description="Niveau de difficulté")
|
||||
alias: Optional[str] = None
|
||||
|
||||
# --- propriétés pratiques ---
|
||||
@property
|
||||
@@ -28,7 +29,7 @@ class Video(BaseModel):
|
||||
@property
|
||||
def title(self) -> str:
|
||||
"""Nom court à afficher."""
|
||||
return self.mp4_file_name or self.file_name
|
||||
return self.alias or self.mp4_file_name or self.file_name
|
||||
|
||||
@property
|
||||
def difficulty_display(self) -> str:
|
||||
|
||||
@@ -44,6 +44,7 @@ def playlist_manual_editor(playlist: Playlist):
|
||||
preselected_labels=preselected,
|
||||
editable_labels=False,
|
||||
editable_difficulty=False,
|
||||
editable_alias=False,
|
||||
playlist=playlist,
|
||||
playlist_video_ids=playlist_video_ids,
|
||||
video_playlists=playlists
|
||||
@@ -129,6 +130,7 @@ def playlist_dynamic_editor(playlist: Playlist):
|
||||
preselected_labels=preselected,
|
||||
editable_labels=False,
|
||||
editable_difficulty=False,
|
||||
editable_alias=False,
|
||||
playlist=playlist,
|
||||
playlist_video_ids=playlist_video_ids,
|
||||
video_playlists=playlists
|
||||
|
||||
@@ -39,7 +39,7 @@ def video_filter_sidebar(unlabeled=False):
|
||||
show_unlabeled_only=show_unlabeled_only
|
||||
)
|
||||
|
||||
def video_list_view(filters: dict, editable_labels=True, editable_difficulty=True, playlist=None):
|
||||
def video_list_view(filters: dict, editable_labels=True, editable_difficulty=True, editable_alias=True, playlist=None):
|
||||
"""Affiche les vidéos selon les filtres fournis."""
|
||||
st.markdown(f"""
|
||||
<style>
|
||||
@@ -93,7 +93,7 @@ def video_list_view(filters: dict, editable_labels=True, editable_difficulty=Tru
|
||||
css_class = "unlabeled" if not preselected else ""
|
||||
with st.container():
|
||||
st.markdown(f"<div class='{css_class}'>", unsafe_allow_html=True)
|
||||
show_video_row(video, preselected, editable_labels, editable_difficulty, playlist)
|
||||
show_video_row(video, preselected, editable_labels, editable_difficulty, editable_alias, playlist)
|
||||
st.markdown("</div>", unsafe_allow_html=True)
|
||||
|
||||
# lazy loading bouton
|
||||
|
||||
@@ -11,6 +11,7 @@ def show_video_row(
|
||||
preselected_labels,
|
||||
editable_labels=True,
|
||||
editable_difficulty=True,
|
||||
editable_alias=True,
|
||||
playlist=None,
|
||||
playlist_video_ids=None,
|
||||
video_playlists=None,
|
||||
@@ -19,7 +20,7 @@ def show_video_row(
|
||||
Affiche une ligne Streamlit pour une vidéo :
|
||||
- miniature + lecture conditionnelle
|
||||
- métadonnées et labels
|
||||
- édition des labels et difficulté
|
||||
- édition des labels, difficulté et alias
|
||||
- (optionnel) ajout/retrait d'une playlist
|
||||
"""
|
||||
|
||||
@@ -100,6 +101,11 @@ def show_video_row(
|
||||
if new_level != video.difficulty_display:
|
||||
db.update_video_difficulty(video.file_name, new_level)
|
||||
st.success(f"Niveau mis à jour pour {video.file_name}")
|
||||
if editable_alias:
|
||||
alias = st.text_input("Alias (optionnel)", value=video.alias, key=f'new_alias_{video.id}')
|
||||
if alias != video.alias:
|
||||
db.update_video_alias(video.file_name, alias.strip())
|
||||
st.success(f"Alias mis à jour pour {video.file_name}")
|
||||
|
||||
# --- Colonne 4 : action playlist ---
|
||||
if col4 and playlist:
|
||||
|
||||
@@ -12,6 +12,7 @@ CREATE TABLE IF NOT EXISTS videos (
|
||||
lat DECIMAL(10,6),
|
||||
long DECIMAL(11,7),
|
||||
address VARCHAR(255),
|
||||
difficulty_level VARCHAR(255) DEFAULT 'Tout niveau'
|
||||
difficulty_level VARCHAR(255) DEFAULT 'Tout niveau',
|
||||
alias VARCHAR(255) DEFAULT ''
|
||||
);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Fonction pour ajouter une ligne à un fichier avec verrouillage (bloquant + timeout + gestion des signaux)
|
||||
append_with_lock() {
|
||||
local line="$1"
|
||||
local file="$2"
|
||||
local lock_dir="/tmp/dancevideos_moved_files.lock"
|
||||
local line="$2"
|
||||
local file="$3"
|
||||
local lock_dir="${file::-4}.lock"
|
||||
local timeout=30 # Timeout en secondes (ajustable)
|
||||
local start_time=$(date +%s)
|
||||
local got_lock=false
|
||||
@@ -10,7 +10,7 @@ append_with_lock() {
|
||||
# Fonction de nettoyage du verrou (appelée en cas de signal ou de sortie)
|
||||
cleanup_lock() {
|
||||
if [ -d "$lock_dir" ]; then
|
||||
rmdir "$lock_dir" 2>/dev/null
|
||||
rmdir "$lock_dir" 2>/dev/null || :
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -38,12 +38,10 @@ append_with_lock() {
|
||||
|
||||
# Écriture dans le fichier (si verrou obtenu)
|
||||
if $got_lock; then
|
||||
set -x
|
||||
echo "$line" >> "$file"
|
||||
echo "$line" >> "$file" # write them twice because of bug where a line is skipped
|
||||
set +x
|
||||
# Libérer le verrou
|
||||
rmdir "$lock_dir"
|
||||
rmdir "$lock_dir" || :
|
||||
trap - INT TERM EXIT # Désactive le piège après utilisation
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -10,8 +10,9 @@ PRINT_ERR=false
|
||||
usage() {
|
||||
echo "Usage: $0 [--all|-a]"
|
||||
echo "Options:"
|
||||
echo " --all, -a Traiter tous les fichiers (ignore la liste de fichiers)"
|
||||
echo " --help, -h Afficher cette aide"
|
||||
echo " --all, -a Traiter tous les fichiers (ignore la liste de fichiers)"
|
||||
echo " --help, -h Afficher cette aide"
|
||||
echo " --print-err, -e Afficher les erreurs en stderr et non dans le fichier de logs"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -25,7 +26,7 @@ while [[ $# -gt 0 ]]; do
|
||||
--help|-h)
|
||||
usage
|
||||
;;
|
||||
--print-err)
|
||||
--print-err|-e)
|
||||
PRINT_ERR=true
|
||||
shift
|
||||
;;
|
||||
@@ -41,7 +42,7 @@ SCRIPTS_DIR=$(dirname `realpath ${BASH_SOURCE[0]}`)
|
||||
# === CONFIGURATION ===
|
||||
export DOSSIER_SOURCE="${HOME}/Downloads"
|
||||
export DOSSIER_DESTINATION_RAW="${HOME}/Documents/.DanceVideos/raw"
|
||||
export TEMP_FILE="/tmp/dancevideos_moved_files.txt"
|
||||
export TEMP_FILE="/tmp/dancevideos_moved_files_$RANDOM.txt"
|
||||
|
||||
# Initialiser le fichier temporaire
|
||||
> "$TEMP_FILE"
|
||||
@@ -108,7 +109,6 @@ mp4_dir() {
|
||||
local dir=$DOSSIER_DESTINATION_MP4
|
||||
dir=$dir/$(date -jf "%Y-%m-%dT%H:%M:%S" "$(get_creation_time $raw)" +%Y%m%d_%H%M%S)
|
||||
dir=${dir}_${weekday}_${address}
|
||||
mkdir -p $dir
|
||||
echo $dir
|
||||
}
|
||||
export -f mp4_dir
|
||||
@@ -127,8 +127,42 @@ write_mp4() {
|
||||
}
|
||||
export -f write_mp4
|
||||
|
||||
generate_funny_suffix() {
|
||||
local file="$1"
|
||||
|
||||
# Grande liste de suffixes uniques et lisibles
|
||||
local funny_names=(
|
||||
"pamplemousse" "canard" "yolo" "flan" "tortue" "biscotte" "poney" "baguette"
|
||||
"chaussette" "banane" "hippopotame" "tuba" "bretzel" "chocolatine" "carambar"
|
||||
"frometon" "krokmou" "gnocchi" "clafoutis" "capybara" "choubidou" "pingouin"
|
||||
"maracas" "raclette" "saucisson" "pistache" "chamallow" "boomerang" "pirouette"
|
||||
"moustache" "abricot" "falafel" "pouet" "zouzou" "cornichon" "gnouf" "mouette"
|
||||
"paprika" "crouton" "galipette" "gratin" "pouliche" "brocoli" "nugget"
|
||||
)
|
||||
|
||||
# Calcul du hash MD5 compatible macOS
|
||||
local hash_val
|
||||
hash_val=$(md5 -q "$file" 2>/dev/null)
|
||||
|
||||
# Fallback si le hash échoue (ex: fichier non lisible)
|
||||
if [[ -z "$hash_val" ]]; then
|
||||
echo "default"
|
||||
return
|
||||
fi
|
||||
|
||||
# Extraire les 8 derniers caractères hexadécimaux pour faire un modulo fiable
|
||||
local short_hex="${hash_val: -8}"
|
||||
|
||||
# Convertir en entier et choisir un mot dans la liste
|
||||
local index=$(( 0x$short_hex % ${#funny_names[@]} ))
|
||||
|
||||
echo "${funny_names[$index]}"
|
||||
}
|
||||
export -f generate_funny_suffix
|
||||
|
||||
process_raw_file() {
|
||||
local raw="$1"
|
||||
local dir_suffixe="${2:-}"
|
||||
|
||||
local ct weekday duration lat lon address
|
||||
IFS="|" read -r ct weekday duration lat lon address <<<"$(process_video "$raw")"
|
||||
@@ -138,6 +172,8 @@ process_raw_file() {
|
||||
# TODO
|
||||
|
||||
local dir=$(mp4_dir $raw $weekday "$address")
|
||||
[ -n "$dir_suffixe" ] && dir=${dir}_${dir_suffixe} || :
|
||||
mkdir -p $dir
|
||||
|
||||
local thumbnail=${dir}/thumbnail.jpg
|
||||
$(write_thumbnail $raw $thumbnail)
|
||||
@@ -166,7 +202,8 @@ export -f screen_video
|
||||
whatsapp_video() {
|
||||
local raw="$1"
|
||||
echo whatsapp $raw
|
||||
process_raw_file $raw
|
||||
local suffixe=$(generate_funny_suffix $raw)
|
||||
process_raw_file $raw $suffixe
|
||||
}
|
||||
export -f whatsapp_video
|
||||
|
||||
@@ -215,9 +252,17 @@ $PRINT_ERR || exec 2> /tmp/DanceVideos.stderr
|
||||
convert_raws
|
||||
|
||||
set -x
|
||||
if [ 0 -lt $(wc -l /tmp/dancevideos_moved_files.txt | awk '{print $1}') ]; then
|
||||
if [ 0 -lt $(wc -l $TEMP_FILE | awk '{print $1}') ]; then
|
||||
|
||||
STREAMLIT_PID=$(ps aux | grep streamlit | grep -v 'grep' | awk '{print $2}'); [ ! -z "$STREAMLIT_PID" ] && kill $STREAMLIT_PID
|
||||
(cd $SCRIPTS_DIR/..; source .venv/bin/activate; streamlit run app/app.py -- --unlabeled)
|
||||
set +o pipefail
|
||||
STREAMLIT_PID="$(ps aux | grep streamlit | grep -v 'grep' | awk '{print $2}')"
|
||||
set -o pipefail
|
||||
if [ ! -z "$STREAMLIT_PID" ]; then
|
||||
kill $STREAMLIT_PID
|
||||
fi
|
||||
# (cd $SCRIPTS_DIR/..; source .venv/bin/activate; streamlit run app/app.py -- --unlabeled &)
|
||||
ROOT=$(realpath $SCRIPTS_DIR/..)
|
||||
source $ROOT/.venv/bin/activate
|
||||
streamlit run $ROOT/app/app.py -- --unlabeled &
|
||||
|
||||
fi
|
||||
@@ -16,12 +16,50 @@ mkdir -p "$DOSSIER_PLAYLIST"
|
||||
# ln -s "$v" "$PLAYLIST_ALL/$(basename "$(dirname "$v")").mp4"
|
||||
# done < <(sqlite3 "$DANCE_VIDEOS_DB" "SELECT rotated_file FROM videos WHERE rotated_file IS NOT NULL;")
|
||||
|
||||
video_filename () {
|
||||
local rotated_file=$1
|
||||
local alias=${2:-}
|
||||
local count_or_music=${3:-}
|
||||
|
||||
name_part="$(basename "$(dirname "$rotated_file")")"
|
||||
# Décomposer le name_part pour insérer l'alias après la date
|
||||
# On suppose un schéma de départ du type YYYYMMDD_HHMMSS...
|
||||
if [[ "$name_part" =~ ^([0-9]{8})_([0-9]{6}.*)$ ]]; then
|
||||
date_part="${BASH_REMATCH[1]}"
|
||||
rest_part="${BASH_REMATCH[2]}"
|
||||
else
|
||||
echo unexpected format >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
output_name="${date_part:2}" #ignore the 20 from 20xx years
|
||||
|
||||
if [[ -n "$alias" ]]; then
|
||||
# Nettoyer l'alias pour le rendre sûr dans le nom de fichier
|
||||
safe_alias="$(echo "$alias" | tr ' /' '_' | tr -dc '[:alnum:]_')"
|
||||
output_name="${output_name}_${safe_alias}"
|
||||
fi
|
||||
|
||||
if [[ -n "$count_or_music" ]]; then
|
||||
output_name="${output_name}_${count_or_music}"
|
||||
fi
|
||||
|
||||
echo "${output_name}_${rest_part}.mp4"
|
||||
}
|
||||
|
||||
# Pour chaque playlist, créer un dossier et ajouter les liens symboliques
|
||||
sqlite3 -separator '|' "$DANCE_VIDEOS_DB" "
|
||||
SELECT pv.playlist_id, pv.playlist_name, pv.video_file_name, v.rotated_file
|
||||
SELECT pv.playlist_id, pv.playlist_name, pv.video_file_name, v.rotated_file, v.alias, COALESCE( count_or_music_labels.count_or_music , '') count_or_music
|
||||
FROM playlist_videos pv JOIN videos v ON pv.video_file_name=v.file_name
|
||||
LEFT JOIN (
|
||||
select * from video_labels
|
||||
natural join (
|
||||
select id as label_id, CASE WHEN name='comptes' THEN 'C' ELSE 'M' END as count_or_music
|
||||
from labels where name in ('comptes','en musique')
|
||||
)
|
||||
) count_or_music_labels ON v.file_name=count_or_music_labels.video_file_name
|
||||
WHERE v.rotated_file IS NOT NULL;
|
||||
" | while IFS='|' read -r playlist_id playlist_name video_file_name rotated_file; do
|
||||
" | while IFS='|' read -r playlist_id playlist_name video_file_name rotated_file alias count_or_music; do
|
||||
# Sauter l'en-tête
|
||||
if [[ "$playlist_id" == "playlist_id" ]]; then
|
||||
continue
|
||||
@@ -37,6 +75,11 @@ sqlite3 -separator '|' "$DANCE_VIDEOS_DB" "
|
||||
mkdir -p "$PLAYLIST_DIR"
|
||||
|
||||
# Créer le lien symbolique
|
||||
ln -sf "$rotated_file" "$PLAYLIST_DIR/$(basename "$(dirname "$rotated_file")").mp4"
|
||||
# ln -sf "$rotated_file" "$PLAYLIST_DIR/$(basename "$(dirname "$rotated_file")").mp4"
|
||||
|
||||
|
||||
ln -sf "$rotated_file" "$PLAYLIST_DIR/$(video_filename $rotated_file $alias $count_or_music)"
|
||||
|
||||
set +x
|
||||
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user