Θα έλεγα να μείνει όσο πιο απλό γίνεται τώρα στην αρχή, να το δοκιμάσουν αρκετοί, και μετά θα έρθουν οι ιδέες για βελτίωση :-)
Εμφάνιση 301-309 από 309
-
14-05-25, 14:34 Απάντηση: Πως κατεβάζουμε(πλέον) από το Ertflix.gr ντοκυμαντέρ & σειρές για παρακολούθηση offline? #301
-
14-05-25, 20:05 Απάντηση: Πως κατεβάζουμε(πλέον) από το Ertflix.gr ντοκυμαντέρ & σειρές για παρακολούθηση offline? #302
Να το βαλεις να κατεβαζει τα dash strems γιατι τα hls εχουν προβλημα.
https://www.adslgr.com/forum/threads...=1#post7631818ديميتريس
-
14-05-25, 20:35 Απάντηση: Πως κατεβάζουμε(πλέον) από το Ertflix.gr ντοκυμαντέρ & σειρές για παρακολούθηση offline? #303
-
17-05-25, 01:03 Απάντηση: Πως κατεβάζουμε(πλέον) από το Ertflix.gr ντοκυμαντέρ & σειρές για παρακολούθηση offline? #304
Έτοιμο το πρόγραμμα. Το αρχείο ARRAY_ERTFLIX πάει πλέον στον φάκελο του χρήστη.
Όποτε εάν υπάρχει φάκελος home/pi κάντε διαγραφή.
Δοκιμάστε και εάν έχει κάποιο πρόβλημα εδώ είμαστε. Μονό για οποία επίλυση και προσθήκη θα αργήσει λόγο υποχρεώσεων. Το έχω δοκιμάσει, ελεύθερα μπορείτε να κάνετε οποιαδήποτε προσθήκη
Κώδικας:#!/bin/bash if [ ! -f /home/${USER}/ARRAY_ERTFLIX ]; then cat /dev/null > /home/${USER}/ARRAY_ERTFLIX fi mapfile -t Array_Series_ERTFLIX < /home/${USER}/ARRAY_ERTFLIX #--------------------------------Εισαγωγή link--------------------------------------------------------- if [[ -z "$Array_Series_ERTFLIX" ]]; then while true; do #εισαγωγη links απο ertflix tmpfile=$(mktemp) yad --center --form --fixed \ --field="<span color='#0000FF'>link1</span>:H50" '' \ --width=550 --height=200 --title="Επιλογή link" \ --text="<span font='DejaVu Sans Book 10'>Παρακαλώ εισάγετε τους συνδέσμους των βίντεο.\nΒεβαιωθείτε ότι οι σύνδεσμοι είναι έγκυροι και πλήρεις.\nΣτη συνέχεια πατήστε ΟΚ.</span>" \ --entry-text-maxlen=50 --buttons-layout=center \ --print-partial --button="gtk-quit:252" --button="gtk-ok:0" \ --no-escape --window-icon=insert-link --borders=10 --no-icon \ > "$tmpfile" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then rm -f "$tmpfile" exit elif [[ $response -eq 0 ]]; then links_temp=$(cat "$tmpfile") rm -f "$tmpfile" fi links_ertflix="$links_temp" links_var=$(echo "$links_ertflix" | sed 's/|//g') echo "$links_var" #ελενχος εαν δεν εχει επιλεγη καποιο link if [ -z $links_var ]; then yad --center --fixed --width=500 --height=100 --image="face-embarrassed" --window-icon=gtk-dialog-warning --title="Warning" --text-align=center --button="gtk-quit:1" --timeout 3 --text="<span font='DejaVu Sans Book 4'>\n</span>\ <span font='DejaVu Sans Book 4'>\n</span>\ <span color='#CC2222' font='Sans Bold 12'> Δεν έχει επιλεγεί κάποιο link</span>" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 fi continue #τελος ελενχου εαν δεν εχει επιλεγη καποιο link fi IFS='|' read -r -a link_array_ert <<< "$links_ertflix" declare -a all_mpd_links=() for link in "${link_array_ert[@]}"; do if [[ -n $link ]]; then json_output=$(yt-dlp -F "$link" --dump-json 2>/dev/null) mpd_links=$(echo echo "$json_output" | grep -oP 'https://[^"]*' | grep '\/index.mpd' \ | grep -v '_web' | grep -v '_web_' | grep -v '\.m3u8' | grep -v '\.mp4' |grep -v '\.mp4' | grep -v '\/dash\/' | sed 's/"[^"]*web\/index\.mpd"//g') found_valid_mpd=false wrong_mpd=0 while IFS= read -r url; do if [[ "$url" =~ \.mpd$ ]]; then all_mpd_links+=("$url") found_valid_mpd=true else wrong_mpd=$((wrong_mpd + 1)) fi done <<< "$mpd_links" #Ελεγχος εαν δεν υπαρχουν .mpd if [[ "$found_valid_mpd" == "false" ]] && [[ ${#all_mpd_links[@]} -eq 0 ]]; then yad --center --fixed --width=500 --height=100 --title="Προβληματικό link" \ --image="face-sick" --window-icon=gtk-dialog-warning --text-align=center \ --text="Το link:\n<b>$link</b>\n<span color='#CC2222' font='Sans Bold 12'>Δεν επέστρεψε καμία έγκυρη .mpd URL.</span>" \ --button="gtk-quit:252" --timeout 4 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 fi save_mpd=0 fi #Ελεγχος εαν υπαρχουν .mpd και μια ή περισοτερες url επιστρεφουν λαθος if [ "$wrong_mpd" -eq 1 ]; then authority="έγκυρη" else authority="έγκυρες" fi if [[ "$found_valid_mpd" == "true" ]] && [[ "$wrong_mpd" -ge 1 ]]; then yad --center --fixed --width=500 --height=100 --text-align=center --title="Μερικές .mpd URLs" \ --image=face-monkey --window-icon=gtk-dialog-question \ --text="Το link:\n<b>$link</b>\nΕπιστρέφει ${#all_mpd_links[@]} URLs .mpd\n<span color='#CC2222' font='Sans Bold 12'>Δεν επέστρεψε ${wrong_mpd} ${authority} URLs.</span> Να προστεθούν οι υπόλοιπες .mpd URLs;" \ --button="gtk-quit:252" --button="Όχι:1" --button="Ναι:0" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 elif [[ $response -eq 0 ]]; then save_mpd=1 #continue elif [[ $response -eq 1 ]]; then save_mpd=1 fi fi #Ολα τα url ειναι .mpd if [[ "$found_valid_mpd" == "true" ]] && [[ "$wrong_mpd" -eq 0 ]]; then save_mpd=1 fi #τελος if [[ -n $link ]]; then fi #τελοσ for link in "${link_array_ert[@]}"; do done #Καταργιση των διπλων .mpd και αποθηκευση στο αρχειο ARRAY_ERTFLIX if [ "$save_mpd" == 1 ]; then valid_unique_mpd_links=$(printf "%s\n" "${all_mpd_links[@]}" | grep '\.mpd$' ) valid_unique_mpd_link=$(echo "$valid_unique_mpd_link" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') duplicates=$(printf "%s\n" "${all_mpd_links[@]}" | sort | uniq -c | awk '$1 > 1 { print $2 }') printf "%s\n%s\n" "$duplicates" "$(cat /home/${USER}/ARRAY_ERTFLIX 2>/dev/null)" > /home/${USER}/ARRAY_ERTFLIX sed -i '/^$/d' /home/${USER}/ARRAY_ERTFLIX fi yad --center --fixed --width=500 --height=100 --image=dialog-question --title="Continue insert" --text="<span font='DejaVu Sans Book 4'>\n</span>\ <span font='DejaVu Sans Book 10'>Θέλεται να συνεχιστεί η προσθήκη link; Για προσθήκη πατήστε ΟΚ</span>" --button="gtk-quit:252" --button="gtk-cancel:1" --button="gtk-ok:0" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 elif [[ $response -eq 0 ]]; then continue elif [ $response -eq 1 ]; then break fi #τελοσ while true; do done fi #---------------------------------------Εισαγωγή απο αρεχεο ertflix-------------------------------------------- current_audio_array="" current_video_array="" y=0 select=0 while true; do mapfile -t Array_Series_ERTFLIX < /home/${USER}/ARRAY_ERTFLIX if [[ "${#Array_Series_ERTFLIX[@]}" -gt 0 ]]; then yad --center --fixed --title="Complete File ARRAY_ERTFLIX" --text="<span font='DejaVu Sans Book 20'>\n</span>\ <span font='DejaVu Sans Book 12'>Υπάρχουν ${#Array_Series_ERTFLIX[@]} links για κατέβασμα</span>" \ --window-icon=insert-link --image="insert-link" --text-align=center --button="gtk-quit:252" --width=500 --height=100 --timeout 3 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 fi for (( l=0; l<${#Array_Series_ERTFLIX[@]}; l++ )); do links=$(echo ${Array_Series_ERTFLIX[$l]}) name=$(echo "$links" | awk -F'/' '{print $(NF-1)}') #---------------------------------------ΑΛΛΑΓΗ ΟΝΟΜΑΤΟΣ ΜΕ YAD------------------------------------------- yad --center --fixed --width=500 --height=100 --image="face-uncertain" --window-icon=gtk-dialog-info --text-align=center --timeout 6 \ --title="ΑΛΛΑΓΗ ΟΝΟΜΑΤΟΣ" \ --text="<span font='DejaVu Sans Book 4'>\n</span>\ <span font='DejaVu Sans Book 12'>Το ονομα ειναι του video ειναι:</span> <span color='#CC2222' font='DejaVu Sans Book 12'>${name}</span> <span font='DejaVu Sans Book 12'>Θέλετε να αλλάξετε το όνομα;</span> <span font='DejaVu Sans Book 12'>Για αλλαγή πατήστε ΟΚ</span>" \ --button="gtk-quit:252" --button="gtk-cancel:1" --button="gtk-ok:0" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit elif [[ $response -eq 1 ]]; then name="$name" elif [[ $response -eq 0 ]]; then tmpname=$(mktemp) while true; do yad --center --form --fixed --text-align=center \ --field="<span color='#0000FF'>Όνομα</span>:H50" '' \ --width=550 --height=200 --title="Εισαγωγή Ονόματος" \ --entry-text-maxlen=50 --buttons-layout=center \ --button="gtk-quit:252" --button="gtk-ok:0" --no-escape \ --window-icon=insert-link --borders=10 --no-icon 2>/dev/null \ --text="<span color='#CC2222' font='DejaVu Sans Book 12'>Το παλιό ονομα ειναι: ${name}</span> <span font='DejaVu Sans Book 12'>Παρακαλώ εισάγετε το καινούργιο όνομα του βίντεο. Στη συνέχεια πατήστε ΟΚ.</span>" > "$tmpname" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then rm -f "$tmpname" exit elif [ $response -eq 0 ]; then name_input=$(cat "$tmpname") rm -f "$tmpname" fi name_input=$(echo "$name_input" | sed 's/|//g') # Έλεγχος αν είναι κενό if [ -z "$name_input" ]; then yad --center --fixed --width=500 --height=100 \ --image="face-angry" --window-icon=gtk-dialog-warning \ --title="Warning" --text-align=center --button="gtk-quit:252" --timeout=3 \ --text="<span font='DejaVu Sans Book 10'>\n</span>\ <span font='DejaVu Sans Book 10'>\n</span>\ <span color='#CC2222' font='Sans Bold 12'>Δεν έχει επιλεγεί κάποιο όνομα</span>" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then rm -f "$tmpname" exit 0 fi continue elif [ -n "$name_input" ]; then name="$name_input" break fi break done fi #---------------------------------------ΠΕΡΝΕΙ ΣΕ ΜΕΤΑΒΛΗΤΕΣ ΤΗΣ ΕΠΙΛΟΓΕΣ ΤΩΝ AUDIO KAI VIDEO------------------------------------------- yad --center \ --title="Preparing a Video" \ --text-align=center \ --window-icon=gtk-dialog-info \ --button="gtk-quit:252" \ --fixed \ --width=550 \ --height=120 \ --timeout=3 \ --image="face-angel" \ --text="<span font='DejaVu Sans Book 1'>\n</span> <span font='DejaVu Sans Book 12'>Γίνεται προετοιμασία</span> <span color='#0000FF' font='DejaVu Sans Book 12'>Για το: ${name}</span> <span font='DejaVu Sans Book 12'>Παρακαλώ περιμένετε...</span>" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 fi audio=$(yt-dlp -F $links | grep audio) readarray -t array_audio <<< "$audio" video=$(yt-dlp -F $links | grep video) readarray -t array_video <<< "$video" # Έλεγχος εάν υπάρχει best has_best=false for entry in "${array_video[@]}"; do if [[ "$entry" == *"(best)"* ]]; then has_best=true break fi done # Αν δεν υπάρχει "(best)", πρόσθεσέ το στην τελευταία γραμμή if [ "$has_best" = false ]; then last_index=$((${#array_video[@]} - 1)) array_video[$last_index]="${array_video[$last_index]} (best)" fi #------------------------------------------------Επανελενχος Audio-------------------------------------- if [[ $select -eq 1 ]]; then current_audio_array_great=$((current_audio_array+25)) current_audio_array_litle=$((current_audio_array-25)) for (( m=0; m<${#array_audio[@]}; m++ )); do audio_bit=$(echo "${array_audio[$m]}" | sed -n 's/.*audio only[^0-9]*\([0-9]\{2,3\}\)k.*/\1/p') audio_bit=$(echo "$audio_bit" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') if [ "$audio_bit" == "$current_audio_array" ] || [ "$audio_bit" -ge "$current_audio_array_litle" -a "$audio_bit" -le "$current_audio_array_great" ]; then audio_bit=$( echo "${array_audio[$m]}" | sed -n 's/.*audio only[^0-9]*\([0-9]\{2,3\}\)k.*/\1/p' | sed 's/$/k/') audio_bit=$(echo "$audio_bit" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') audio_var=$( echo "${array_audio[$m]}" | sed -n 's/.*audio=\([0-9]\+\).*/audio=\1/p') audio_difference=1 break else audio_difference=0 fi done #------------------------------------------------Επανελενχος video-------------------------------------- current_video_array1=$( echo $current_video_array | grep -w "(best)" ) if [ -n "$current_video_array1" ]; then for (( n=0; n<${#array_video[@]}; n++ )); do current_video_array2=$( echo "${array_video[$n]}" | grep -w "(best)" | sed -n 's/.*x\([0-9]\+\).*/\1/p' | sed 's/$/ (best)/' ) if [ -n "$current_video_array2" ]; then break fi done if [ "$current_video_array2" == "$current_video_array1" ]; then video_bit=$(echo "${array_video[$n]}" | sed -n 's/.*x\([0-9]\+\).*/\1/p' | sed 's/$/p/; s/$/ (best)/' ) video_var=$(echo "${array_video[$n]}" | sed -n 's/^video=\([0-9]\+\).*/video=\1/p') video_difference=1 elif [ "$current_video_array2" != "$current_video_array1" ]; then current_video_array1=$(echo "$current_video_array1" | grep -o '[0-9]\+') current_video_array2=$(echo "$current_video_array2" | grep -o '[0-9]\+') echo $current_video_array1 echo $current_video_array2 current_video_array_great=$((current_video_array1+25)) current_video_array_litle=$((current_video_array1-25)) if [ "$current_video_array2" -ge "$current_video_array_litle" ] && [ "$current_video_array2" -le "$current_video_array_great" ]; then video_bit=$(echo "${array_video[$n]}" | sed -n 's/.*x\([0-9]\+\).*/\1/p' | sed 's/$/p/; s/$/ (best)/' ) video_var=$(echo "${array_video[$n]}" | sed -n 's/^video=\([0-9]\+\).*/video=\1/p') video_difference=1 else video_difference=0 fi fi elif [ -z "$current_video_array1" ]; then current_video_array_great=$((current_video_array+25)) current_video_array_litle=$((current_video_array-25)) for (( n=0; n<${#array_video[@]}; n++ )); do video_bit2=$(echo "${array_video[$n]}" | sed -n 's/.*x\([0-9]\+\).*/\1/p') if [ "$video_bit2" == "$current_video_array" ] || [ "$video_bit2" -ge "$current_video_array_litle" -a "$video_bit2" -le "$current_video_array_great" ]; then video_bit=$(echo "${array_video[$n]}" | sed -n 's/.*x\([0-9]\+\).*/\1/p'| sed 's/$/p/') video_var=$(echo "${array_video[$n]}" | sed -n 's/^video=\([0-9]\+\).*/video=\1/p') video_difference=1 break else video_difference=0 fi done fi #------------------------------------------------Η Διένεξη της δήλωσης σε YAD-------------------------------------- if [[ "$audio_difference" -eq 0 && "$video_difference" -eq 0 ]]; then yad --center --fixed --title="Difference a Video/Audio" --text="<span font='DejaVu Sans Book 16'>\n</span>\ <span color='#CC2222' font='DejaVu Sans Book 12'>Υπάρχει διένεξη της δήλωσης του video-audio με πριν. Πρέπει να δηλωθεί πάλι.</span>" \ --window-icon=gtk-dialog-info --text-align=center --image="face-devilish" --no-buttons --width=550 --height=100 --timeout 4 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 fi select=0 elif [[ "$audio_difference" -eq 0 && "$video_difference" -eq 1 ]]; then yad --center --fixed --title="Difference a Audio" --text="<span font='DejaVu Sans Book 16'>\n</span>\ <span color='#CC2222' font='DejaVu Sans Book 12'>Υπάρχει διένεξη της δήλωσης του audio με πριν. Πρέπει να δηλωθεί πάλι.</span>" \ --window-icon=gtk-dialog-info --text-align=center --image="face-devilish" --no-buttons --width=550 --height=100 --timeout 4 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 fi select=0 elif [[ "$audio_difference" -eq 1 && "$video_difference" -eq 0 ]]; then yad --center --fixed --title="Preparing a Video" --text="<span font='DejaVu Sans Book 16'>\n</span>\ <span color='#CC2222' font='DejaVu Sans Book 12'>Υπάρχει διένεξη της δήλωσης του video με πριν. Πρέπει να δηλωθεί πάλι.</span>" \ --window-icon=gtk-dialog-info --text-align=center --image="face-devilish" --no-buttons --width=550 --height=100 --timeout 4 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 fi select=0 elif [[ "$audio_difference" -eq 1 && "$video_difference" -eq 1 ]]; then select=1 fi fi #----------------------------------------------------ΕΠΙΛΟΓΗ "MENU" AUDIO ----------------------------------------------------------- if [[ $select -eq 0 ]]; then tmpaudio=$(mktemp) while true; do audio_bitrate_list=() # Δημιουργία λίστας με καθαρά bitrate (π.χ. 128k, 256k) for audio_bitrate in "${array_audio[@]}"; do audio_bit1=$(echo "$audio_bitrate" | sed -n 's/.*audio only[^0-9]*\([0-9]\{2,3\}\)k.*/\1/p' | sed 's/$/k/') audio_bitrate_list+=("$audio_bit1") done #Παρουσίαση YAD Εμφάνιση επιλογών yad --center --title="Επιλογή ήχου" --list --borders=10 --no-headers --image="sound" --window-icon=media-audio \ --width=500 --height=260 --column=List --button="gtk-quit:252" --button="gtk-cancel:1" --button="gtk-ok:0" \ --text="<span font='DejaVu Sans Book 4'>\n</span> \ <span font='DejaVu Sans Book 11'>Επίλεξε ένα στοιχείο Bitrate για ήχο από τη λίστα</span>" \ "${audio_bitrate_list[@]}" > "$tmpaudio" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then rm -f "$tmpaudio" exit fi if [[ $response -eq 0 ]]; then selected_audio=$(cat "$tmpaudio") selected_audio=$(echo "$selected_audio" | tr -d '|') rm -f "$tmpaudio" break fi if [[ $response -eq 1 ]]; then yad --center --fixed --width=500 --height=100 --image=dialog-warning --window-icon=gtk-dialog-warning --title="Warning" \ --text-align=center --button="gtk-quit:252" --timeout 3 --text="<span font='DejaVu Sans Book 4'>\n</span>\ <span font='DejaVu Sans Book 4'>\n</span>\ <span color='#CC2222' font='Sans Bold 12'>Δεν έχει γίνει επιλογή Bitrate για ήχο</span>" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then rm -f "$tmpaudio" exit 0 else continue fi fi done # -----------------------------Εύρεση του bitrate και του format ID που ταιριάζει στην επιλογή audio i=0 for audio_bitrate in "${array_audio[@]}"; do audio_bit=$(echo "$audio_bitrate" | sed -n 's/.*audio only[^0-9]*\([0-9]\{2,3\}\)k.*/\1/p' | sed 's/$/k/') if [ "$selected_audio" == "$audio_bit" ]; then audio_var=$(echo "${array_audio[$i]}" | sed -n 's/.*audio=\([0-9]\+\).*/audio=\1/p') break fi i=$((i+1)) done #bitrate μόνο η τιμή current_audio_array=$( echo "${array_audio[$i]}" | sed -n 's/.*audio only[^0-9]*\([0-9]\{2,3\}\)k.*/\1/p') #----------------------------------------------------ΕΠΙΛΟΓΗ "MENU" VIDEO----------------------------------------------------------- tmpvideo=$(mktemp) while true; do video_list=() for video_bitrate in "${array_video[@]}"; do video_resource=$( echo "$video_bitrate" | grep -w "(best)" ) video_bit1=$(echo "${video_bitrate}" | sed -n 's/.*x\([0-9]\+\).*/\1/p'| sed 's/$/p/') if [ -z "$video_resource" ]; then video_bit1="${video_bit1}" elif [ -n "$video_resource" ]; then video_bit1="${video_bit1} (best)" fi video_list+=("$video_bit1") done #Παρουσίαση YAD Εμφάνιση επιλογών yad --center --title="Επιλογή Βίντεο" --list \ --text="<span font='DejaVu Sans Book 4'>\n</span> \ <span font='DejaVu Sans Book 11'>Επίλεξε ένα στοιχείο Resolution για βίντεο από τη λίστα</span>" \ --borders=10 --image="video-x-generic" --no-headers --window-icon=media-video \ --button="gtk-quit:252" --button="gtk-cancel:1" --button="gtk-ok:0" \ --width=500 --height=260 --column=List "${video_list[@]}" > "$tmpvideo" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then rm -f "$tmpvideo" exit fi if [[ $response -eq 0 ]]; then selected_video=$(cat "$tmpvideo") selected_video=$(echo "$selected_video" | tr -d '|') rm -f "$tmpvideo" break fi if [[ $response -eq 1 ]]; then yad --center --fixed --width=500 --height=100 --image=dialog-warning --window-icon=gtk-dialog-warning --title="Warning" \ --text-align=center --button="gtk-quit:252" --timeout 3 --text="<span font='DejaVu Sans Book 4'>\n</span>\ <span font='DejaVu Sans Book 4'>\n</span>\ <span color='#CC2222' font='Sans Bold 12'>Δεν έχει γίνει επιλογή Resolution για βίντεο</span>" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then rm -f "$tmpvideo" exit 0 else continue fi fi done # --------------------------Εύρεση του resolution και του format ID που ταιριάζει στην επιλογή video v=0 for video_bitrate in "${array_video[@]}"; do video_resource=$( echo "$video_bitrate" | grep -w "(best)" ) video_bit1=$(echo "${video_bitrate}" | sed -n 's/.*x\([0-9]\+\).*/\1/p'| sed 's/$/p/') #video_bit1=$(echo "$video_bit1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') if [ -z "$video_resource" ]; then if [ "$selected_video" == "$video_bit1" ]; then video_bit=$(echo "${array_video[$v]}" | sed -n 's/.*x\([0-9]\+\).*/\1/p'| sed 's/$/p/') video_var=$(echo "${array_video[$v]}" | sed -n 's/^video=\([0-9]\+\).*/video=\1/p') break fi elif [ -n "$video_resource" ]; then video_bit1="${video_bit1} (best)" if [ "$selected_video" == "$video_bit2" ]; then video_bit=$(echo "${array_video[$v]}" | sed -n 's/.*x\([0-9]\+\).*/\1/p'| sed 's/$/p/; s/$/ (best)/') video_var=$(echo "${array_video[$v]}" | sed -n 's/^video=\([0-9]\+\).*/video=\1/p') break fi fi v=$((v+1)) done #resolution που κραταει if [ -z "$video_resource" ]; then current_video_array=$( echo ${array_video[$v]} | sed -n 's/.*x\([0-9]\+\).*/\1/p') elif [ -n "$video_resource" ]; then current_video_array=$( echo ${array_video[$v]} | sed -n 's/.*x\([0-9]\+\).*/\1/p' | sed 's/$/ (best)/') fi #-------------------------------------------Επιλογή φακέλου αποθήκευσης----------------------------------------------------------------- tempdir=$(mktemp) while true; do yad --file-selection --directory --text-align=center --title="Φάκελοι" --text-align=center --text="<span font='DejaVu Sans Book 4'>\n</span>\ <span color='#0000FF' font='DejaVu Sans Book 12'>Επιλογή φακέλου αποθήκευσης</span>" --window-icon=gtk-directory --center --width=900 --height=900 --on-top \ --button="gtk-quit:252" --button="gtk-cancel:1" --button="gtk-ok:0" > "$tempdir" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then rm -f "$tempdir" exit fi if [[ $response -eq 0 ]]; then output_dir=$(cat "$tempdir") output_dir=$(echo "$output_dir" | tr -d '|') rm -f "$tempdir" break fi if [[ $response -eq 1 ]]; then yad --center --fixed --width=500 --height=100 --image="face-tired" --window-icon=gtk-dialog-warning --title="Warning" \ --text-align=center --button="gtk-quit:252" --timeout 3 --text="<span font='DejaVu Sans Book 4'>\n</span>\ <span font='DejaVu Sans Book 4'>\n</span>\ <span color='#CC2222' font='Sans Bold 12'> Δεν επιλέχθηκε φάκελος αποθήκευσης</span>" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then rm -f "$tempdir" exit 0 else continue fi fi done yad --center --fixed --width=600 --height=200 --text="<span font='DejaVu Sans Book 12'> Ονομα: ${name} Επιλογή Ήχου: ${audio_bit} ${audio_var} Επιλογή Βίντεο: ${video_bit} ${video_var} Επιλογή Φακέλου αποθήκευσης: ${output_dir}'</span>\n \ <span color='#CC2222' font='DejaVu Sans Book 12'>Θέλετε να της κρατήσετε οριστικά;</span>" \ --image="face-uncertain" --text-align=center --button="gtk-quit:252" --button="gtk-no:1" --button="gtk-yes:0" 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 elif [[ $response -eq 0 ]]; then select=1 elif [[ $response -eq 1 ]]; then select=0 fi fi #--------τελος if select=0 ----------------------Downloading Video/Audio-------------------------------------------------------- video=$(echo "${video_var}[ext=mp4]+${audio_var}[ext=m4a]/bestvideo+bestaudio") ( yt-dlp -f $video -o "$output_dir/${name}.${video_bit}-${audio_bit}.ERTFLIX.%(ext)s" --merge-output-format mp4 $links --newline \ | while read -r line; do progress=$(echo "$line" | grep --line-buffered -oP '^\[download\].*?\K([0-9.]+\%|#\d+ of \d)') if [[ -n $progress ]]; then percent=$(echo "$progress" | grep -oP '[0-9.]+') new_percent=$(awk -v p="$percent" 'BEGIN{printf "%.0f%%", p-0.8}') echo "$new_percent" fi echo "$line" done \ | tee >(grep "%" | sed -u "s/\(.*\)%\ \([0-9\.]*\)\(.*\)/\2\n# \1\2% \3/") \ ) | yad --center --width=550 --height=100 --progress --title="Downloading Video/Audio..." --text="<span font='DejaVu Sans Book 4'>\n</span> \ <span font='DejaVu Sans Book 11'>Please wait..${name}: ${video_bit} - ${audio_bit}</span>" \ --auto-close --no-buttons --borders=10 --scroll 2>/dev/null #-----------------------------------------Download completed--Abort Download--OR--NOT------------------------------------------------- yad --center --info --fixed --image="face-kiss" --no-buttons --title="Download Complete" --text-align=center --text="<span font='DejaVu Sans Book 16'>\n</span> \ <span color='#0000FF' font='DejaVu Sans Book 12'>Download completed successfully! \n ${name}</span>" --width=500 --height=100 --timeout 5 2>/dev/null delete_line=1 sed -i "${delete_line}d" /home/${USER}/ARRAY_ERTFLIX y=$((y+1)) mapfile -t Array_Series_ERTFLIX < /home/${USER}/ARRAY_ERTFLIX if [[ "${#Array_Series_ERTFLIX[@]}" -gt 1 && "$y" -ge 1 ]]; then yad --center --fixed --text-align=center --width=500 --height=50 \ --title="Abort Download" \ --text="<span font='DejaVu Sans Book 18'>\n</span>Επέλεξε Ναι για σταμάτημα." \ --button="Ναι":0 \ --timeout=7 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 elif [[ $response -eq 0 ]]; then yad --center --fixed --image="face-sad" --text-align=center --width=500 --height=80 --no-buttons --title="Download Complete All" \ --text="<span font='DejaVu Sans Book 12'>\n</span> \ <span color='#CC2222' font='DejaVu Sans Book 12'>Download aborted</span>" --timeout 3 2>/dev/null exit else yad --center --fixed --image="face-smile-big" --text-align=center --width=500 --height=80 --no-buttons --title="Download Complete All" \ --text="<span font='DejaVu Sans Book 12'>\n</span> \ <span color='#0000FF' font='DejaVu Sans Book 12'>Continuing download...</span>" --timeout 3 2>/dev/null break 1 fi fi done #-----------------------------------------END------------------------------------------------- elif [[ "${#Array_Series_ERTFLIX[@]}" -eq 0 ]]; then yad --center --info --fixed --image="face-cool" --text-align=center --width=500 --height=100 --no-buttons --title="Download Complete All" --text="<span font='DejaVu Sans Book 12'>\n</span> \ <span color='#0000FF' font='DejaVu Sans Book 12'>Δεν υπάρχουν links για κατέβασμα\n \ Φτάσατε στο τέλος</span>" --timeout 5 2>/dev/null response=$? if [[ $response -eq 252 ]]; then exit 0 fi exit fi done fi
Τελευταία επεξεργασία από το μέλος microvio : 17-05-25 στις 08:29.
-
17-05-25, 07:20 Απάντηση: Πως κατεβάζουμε(πλέον) από το Ertflix.gr ντοκυμαντέρ & σειρές για παρακολούθηση offline? #305ديميتريس
-
17-05-25, 16:42 Απάντηση: Πως κατεβάζουμε(πλέον) από το Ertflix.gr ντοκυμαντέρ & σειρές για παρακολούθηση offline? #306
To αντίστοιχο python gui script για Windows!
Εγκατάσταση της Python (με την επιλογή "Add Python to PATH").
Λήψη του yt-dlp.exe και τοποθέτησή του είτε στον ίδιο φάκελο με το script είτε σε έναν φάκελο που βρίσκεται στο PATH.
Αποθηκεύστε τον παρακάτω κώδικα ως ένα αρχείο Python (π.χ., ertflix_gui_downloader.py).
Κατεβάστε το yt-dlp.exe από την επίσημη σελίδα του (https://github.com/yt-dlp/yt-dlp/rel...oad/yt-dlp.exe) και τοποθετήστε το στον ίδιο φάκελο με το ertflix_gui_downloader.py.
Ανοίξτε μια γραμμή εντολών (Command Prompt ή PowerShell) στον φάκελο όπου αποθηκεύσατε τα αρχεία και εκτελέστε:
python ertflix_gui_downloader.py
Χρήση Εφαρμογής:
Εισάγετε έναν σύνδεσμο ERTFlix στο πεδίο και πατήστε "Προσθήκη" (ή Enter).
Οι σύνδεσμοι θα εμφανιστούν στη λίστα.
Πατήστε "Έναρξη Λήψεων".
Για κάθε σύνδεσμο, θα εμφανιστεί ένα παράθυρο διαλόγου για να:
Επιβεβαιώσετε/αλλάξετε το όνομα του αρχείου.
Επιλέξετε ποιότητα βίντεο.
Επιλέξετε ποιότητα ήχου.
Επιλέξετε φάκελο αποθήκευσης (ο τελευταίος φάκελος αποθηκεύεται).
Πατήστε "ΟΚ" στο διάλογο για να ξεκινήσει η λήψη του συγκεκριμένου βίντεο.
Η γραμμή προόδου και η κατάσταση θα ενημερώνονται.
Μπορείτε να πατήσετε "Διακοπή" για να σταματήσετε την τρέχουσα λήψη και τις επόμενες.
"Αφαίρεση Επιλεγμένου" και "Εκκαθάριση Λίστας" διαχειρίζονται τη λίστα συνδέσμων.
Οι σύνδεσμοι αποθηκεύονται στο ertflix_links.txt και ο τελευταίος φάκελος λήψης στο downloader_config.json
Δεν χρειάζεται να εγκαταστήσετε επιπλέον πακέτα Python μέσω pip (όπως pip install some_package) για να τρέξει αυτό το συγκεκριμένο script, καθώς όλες οι χρησιμοποιούμενες βιβλιοθήκες Python είναι μέρος της standard library.
Κώδικας:import tkinter as tk from tkinter import ttk, filedialog, messagebox import subprocess import threading import os import re import json # --- Configuration --- YT_DLP_PATH = "yt-dlp.exe" # Or full path if not in same directory/PATH LINKS_FILE = "ertflix_links.txt" CONFIG_FILE = "downloader_config.json" # Για αποθήκευση τελευταίου φακέλου class ErtflixDownloaderApp: def __init__(self, root): self.root = root self.root.title("ERTFlix Downloader") self.root.geometry("800x600") self.links_to_download = [] self.current_download_thread = None self.stop_download_flag = threading.Event() self.last_save_directory = self.load_last_config().get("last_save_directory", os.path.expanduser("~\\Downloads")) self.last_audio_quality_id = None # Θα αποθηκεύουμε το ID του format self.last_video_quality_id = None # Θα αποθηκεύουμε το ID του format self.setup_ui() self.load_links_from_file() def load_last_config(self): if os.path.exists(CONFIG_FILE): try: with open(CONFIG_FILE, 'r', encoding='utf-8') as f: return json.load(f) except json.JSONDecodeError: return {} except Exception: # Catch other potential errors during file reading return {} return {} def save_last_config(self): config = { "last_save_directory": self.last_save_directory, "last_audio_quality_id": self.last_audio_quality_id, "last_video_quality_id": self.last_video_quality_id } try: with open(CONFIG_FILE, 'w', encoding='utf-8') as f: json.dump(config, f) except Exception as e: print(f"Error saving config: {e}") def setup_ui(self): # --- Frame for Link Input --- input_frame = ttk.LabelFrame(self.root, text="Εισαγωγή Συνδέσμου ERTFlix") input_frame.pack(padx=10, pady=10, fill="x") self.link_entry = ttk.Entry(input_frame, width=80) self.link_entry.pack(side=tk.LEFT, padx=5, pady=5, expand=True, fill="x") self.link_entry.bind("<Return>", lambda event: self.add_link()) add_button = ttk.Button(input_frame, text="Προσθήκη", command=self.add_link) add_button.pack(side=tk.LEFT, padx=5, pady=5) # --- Frame for Links List --- list_frame = ttk.LabelFrame(self.root, text="Λίστα Συνδέσμων") list_frame.pack(padx=10, pady=5, fill="both", expand=True) self.links_listbox = tk.Listbox(list_frame, selectmode=tk.SINGLE, width=100, height=15) self.links_listbox.pack(side=tk.LEFT, padx=5, pady=5, fill="both", expand=True) scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self.links_listbox.yview) scrollbar.pack(side=tk.RIGHT, fill="y") self.links_listbox.config(yscrollcommand=scrollbar.set) # --- Frame for Controls --- controls_frame = ttk.Frame(self.root) controls_frame.pack(padx=10, pady=5, fill="x") self.start_button = ttk.Button(controls_frame, text="Έναρξη Λήψεων", command=self.start_download_process) self.start_button.pack(side=tk.LEFT, padx=5, pady=5) self.stop_button = ttk.Button(controls_frame, text="Διακοπή", command=self.stop_current_download, state=tk.DISABLED) self.stop_button.pack(side=tk.LEFT, padx=5, pady=5) remove_selected_button = ttk.Button(controls_frame, text="Αφαίρεση Επιλεγμένου", command=self.remove_selected_link) remove_selected_button.pack(side=tk.LEFT, padx=5, pady=5) clear_button = ttk.Button(controls_frame, text="Εκκαθάριση Λίστας", command=self.clear_links) clear_button.pack(side=tk.LEFT, padx=5, pady=5) # --- Frame for Progress and Status --- status_frame = ttk.LabelFrame(self.root, text="Κατάσταση") status_frame.pack(padx=10, pady=10, fill="x") self.status_label = ttk.Label(status_frame, text="Έτοιμο.") self.status_label.pack(side=tk.LEFT, padx=5, pady=5) self.progress_bar = ttk.Progressbar(status_frame, orient="horizontal", length=300, mode="determinate") self.progress_bar.pack(side=tk.LEFT, padx=5, pady=5, expand=True, fill="x") def add_link(self): link = self.link_entry.get().strip() if link: if link.startswith("http://") or link.startswith("https://"): if link not in self.links_to_download: self.links_to_download.append(link) self.links_listbox.insert(tk.END, link) self.link_entry.delete(0, tk.END) self.save_links_to_file() else: messagebox.showwarning("Διπλότυπο", "Αυτός ο σύνδεσμος υπάρχει ήδη στη λίστα.") else: messagebox.showerror("Σφάλμα", "Μη έγκυρος σύνδεσμος. Πρέπει να ξεκινά με http:// ή https://") else: messagebox.showwarning("Κενό Πεδίο", "Παρακαλώ εισάγετε έναν σύνδεσμο.") def remove_selected_link(self): selected_indices = self.links_listbox.curselection() if not selected_indices: messagebox.showinfo("Καμία Επιλογή", "Δεν έχετε επιλέξει σύνδεσμο για αφαίρεση.") return selected_index = selected_indices[0] link_to_remove = self.links_listbox.get(selected_index) if messagebox.askyesno("Επιβεβαίωση Αφαίρεσης", f"Θέλετε σίγουρα να αφαιρέσετε τον σύνδεσμο:\n{link_to_remove} ;"): self.links_listbox.delete(selected_index) if link_to_remove in self.links_to_download: self.links_to_download.remove(link_to_remove) self.save_links_to_file() self.status_label.config(text=f"Αφαιρέθηκε: {link_to_remove}") def load_links_from_file(self): self.links_to_download.clear() self.links_listbox.delete(0, tk.END) if os.path.exists(LINKS_FILE): try: with open(LINKS_FILE, "r", encoding="utf-8") as f: for line in f: link = line.strip() if link and link not in self.links_to_download : self.links_to_download.append(link) self.links_listbox.insert(tk.END, link) except Exception as e: messagebox.showerror("Σφάλμα Φόρτωσης", f"Δεν ήταν δυνατή η φόρτωση συνδέσμων: {e}") def save_links_to_file(self): try: with open(LINKS_FILE, "w", encoding="utf-8") as f: for link in self.links_to_download: f.write(link + "\n") except Exception as e: messagebox.showerror("Σφάλμα Αποθήκευσης", f"Δεν ήταν δυνατή η αποθήκευση συνδέσμων: {e}") def clear_links(self): if messagebox.askyesno("Εκκαθάριση", "Είστε σίγουροι ότι θέλετε να αφαιρέσετε όλους τους συνδέσμους;"): self.links_to_download.clear() self.links_listbox.delete(0, tk.END) self.save_links_to_file() self.status_label.config(text="Η λίστα εκκαθαρίστηκε.") def start_download_process(self): if not self.links_to_download: messagebox.showinfo("Κενή Λίστα", "Δεν υπάρχουν σύνδεσμοι για λήψη.") return if self.current_download_thread and self.current_download_thread.is_alive(): messagebox.showwarning("Σε Εξέλιξη", "Μια λήψη είναι ήδη σε εξέλιξη.") return self.start_button.config(state=tk.DISABLED) self.stop_button.config(state=tk.NORMAL) self.stop_download_flag.clear() # Φόρτωση των τελευταίων επιλογών ποιότητας πριν την έναρξη config = self.load_last_config() self.last_audio_quality_id = config.get("last_audio_quality_id") self.last_video_quality_id = config.get("last_video_quality_id") self.current_download_thread = threading.Thread(target=self._download_worker, daemon=True) self.current_download_thread.start() def stop_current_download(self): if self.current_download_thread and self.current_download_thread.is_alive(): self.status_label.config(text="Προσπάθεια διακοπής...") self.stop_download_flag.set() def _download_worker(self): initial_links_count = len(self.links_to_download) downloaded_count = 0 while self.links_to_download and not self.stop_download_flag.is_set(): link_to_process = self.links_to_download[0] self.root.after_idle(lambda l=link_to_process: self.status_label.config(text=f"Επεξεργασία: {l[:50]}...")) self.root.after_idle(lambda: self.progress_bar.config(value=0)) video_info = None try: proc = subprocess.run( [YT_DLP_PATH, "-F", "--no-warnings", "--dump-json", "--encoding", "utf-8", link_to_process], capture_output=True, text=True, encoding='utf-8', # Ensure utf-8 for output creationflags=subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0 ) # print(f"DEBUG: yt-dlp return code for {link_to_process}: {proc.returncode}") # print(f"DEBUG: yt-dlp stdout for {link_to_process}:\n>>>\n{proc.stdout}\n<<<") # print(f"DEBUG: yt-dlp stderr for {link_to_process}:\n>>>\n{proc.stderr}\n<<<") if proc.returncode != 0: error_message = f"Το yt-dlp απέτυχε για το {link_to_process} (code: {proc.returncode}).\n" if proc.stderr: error_message += f"Stderr:\n{proc.stderr[:500]}" elif proc.stdout: error_message += f"Stdout:\n{proc.stdout[:500]}" else: error_message += "Δεν υπήρξε έξοδος σφάλματος." self.root.after_idle(lambda msg=error_message: messagebox.showerror("Σφάλμα yt-dlp", msg)) self.root.after_idle(self._mark_link_as_failed, link_to_process) continue if not proc.stdout or not proc.stdout.strip(): self.root.after_idle(lambda l=link_to_process: messagebox.showerror("Σφάλμα yt-dlp", f"Το yt-dlp δεν επέστρεψε δεδομένα (κενή έξοδος) για το {l}.")) self.root.after_idle(self._mark_link_as_failed, link_to_process) continue potential_json_lines = proc.stdout.strip().splitlines() parsed_successfully = False for line_content in potential_json_lines: try: video_info_candidate = json.loads(line_content) if isinstance(video_info_candidate, dict) and 'formats' in video_info_candidate: video_info = video_info_candidate parsed_successfully = True break except json.JSONDecodeError: continue if not parsed_successfully or video_info is None: self.root.after_idle(lambda l=link_to_process, out=proc.stdout[:500]: messagebox.showerror("Σφάλμα Ανάλυσης JSON", f"Δεν ήταν δυνατή η ανάλυση της εξόδου JSON από το yt-dlp για το {l}.\nΈξοδος:\n{out}")) self.root.after_idle(self._mark_link_as_failed, link_to_process) continue except json.JSONDecodeError as e_json: # Should be caught by the inner try-except now self.root.after_idle(lambda l=link_to_process, err=str(e_json), out_data=proc.stdout[:500] if 'proc' in locals() else "N/A": messagebox.showerror("Σφάλμα Ανάλυσης JSON", f"Σφάλμα κατά την ανάλυση JSON για {l}:\n{err}\n\nΠρώτες γραμμές εξόδου:\n{out_data}")) self.root.after_idle(self._mark_link_as_failed, link_to_process) continue except Exception as e: self.root.after_idle(lambda l=link_to_process, err=str(e): messagebox.showerror("Γενικό Σφάλμα", f"Άγνωστο σφάλμα κατά την επεξεργασία του {l}:\n{err}")) self.root.after_idle(self._mark_link_as_failed, link_to_process) continue if not video_info: self.root.after_idle(lambda l=link_to_process: messagebox.showerror("Σφάλμα Δεδομένων", f"Δεν ανακτήθηκαν πληροφορίες βίντεο για το {l}.")) self.root.after_idle(self._mark_link_as_failed, link_to_process) continue dialog_result = self.show_format_selection_dialog(video_info) if not dialog_result or self.stop_download_flag.is_set(): if not self.stop_download_flag.is_set(): self.root.after_idle(lambda: self.status_label.config(text="Η λήψη ακυρώθηκε από τον χρήστη.")) break output_name = dialog_result["name"] save_dir = dialog_result["path"] video_format_id = dialog_result["video_id"] audio_format_id = dialog_result["audio_id"] self.last_save_directory = save_dir self.last_audio_quality_id = audio_format_id self.last_video_quality_id = video_format_id self.save_last_config() output_template = os.path.join(save_dir, f"{output_name}.%(ext)s") format_selection = f"{video_format_id}+{audio_format_id}/bv*+ba/b" try: cmd = [ YT_DLP_PATH, "-f", format_selection, "--no-warnings", "--progress", "--newline", "--merge-output-format", "mp4", "-o", output_template, link_to_process ] process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, encoding='utf-8', bufsize=1, universal_newlines=True, creationflags=subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0) for line in process.stdout: if self.stop_download_flag.is_set(): process.terminate() try: process.wait(timeout=5) except subprocess.TimeoutExpired: process.kill() self.root.after_idle(lambda: self.status_label.config(text="Η λήψη διακόπηκε.")) break match = re.search(r"\[download\]\s+([0-9\.]+?%)\s+of", line) if match: percent_str = match.group(1).replace('%', '') try: percent = float(percent_str) self.root.after_idle(lambda p=percent: self.progress_bar.config(value=p)) self.root.after_idle(lambda p=percent, n=output_name: self.status_label.config(text=f"Λήψη {n}: {p:.1f}%")) except ValueError: pass process.wait() if self.stop_download_flag.is_set(): break if process.returncode == 0: self.root.after_idle(lambda n=output_name: self.status_label.config(text=f"Η λήψη του '{n}' ολοκληρώθηκε.")) self.root.after_idle(self._mark_link_as_done, link_to_process) downloaded_count += 1 else: stderr_output = process.stderr.read() if process.stderr else "No stderr output" self.root.after_idle(lambda n=output_name, err=stderr_output: messagebox.showerror("Σφάλμα Λήψης", f"Σφάλμα κατά τη λήψη του '{n}':\n{err[:500]}")) self.root.after_idle(self._mark_link_as_failed, link_to_process) except Exception as e: self.root.after_idle(lambda l=link_to_process, err=str(e): messagebox.showerror("Σφάλμα Εκτέλεσης", f"Σφάλμα κατά την εκτέλεση λήψης για {l}:\n{err}")) self.root.after_idle(self._mark_link_as_failed, link_to_process) continue if self.stop_download_flag.is_set(): self.root.after_idle(lambda: self.status_label.config(text="Οι λήψεις διακόπηκαν.")) break self.root.after_idle(self._on_all_downloads_finished, downloaded_count, initial_links_count) def _mark_link_as_done(self, link): if link in self.links_to_download: try: idx = self.links_to_download.index(link) self.links_listbox.delete(idx) self.links_to_download.pop(idx) self.save_links_to_file() except ValueError: # Link might have been removed by another action pass except Exception as e: print(f"Error marking link as done: {e}") def _mark_link_as_failed(self, link): if link in self.links_to_download: try: idx = self.links_to_download.index(link) self.links_listbox.itemconfig(idx, {'bg':'#FFCCCC', 'fg':'#A60000'}) # Light red background except ValueError: pass # Link not in listbox (maybe already removed) except Exception as e: print(f"Error marking link as failed in listbox: {e}") # We don't remove it automatically, user can retry or remove manually def _on_all_downloads_finished(self, downloaded_count, initial_count): self.start_button.config(state=tk.NORMAL) self.stop_button.config(state=tk.DISABLED) self.progress_bar.config(value=0) if not self.stop_download_flag.is_set(): if initial_count > 0: # Only show messages if there were links to process if downloaded_count == initial_count: self.status_label.config(text="Όλες οι λήψεις ολοκληρώθηκαν!") messagebox.showinfo("Ολοκλήρωση", "Όλες οι λήψεις ολοκληρώθηκαν με επιτυχία!") else: failed_count = initial_count - downloaded_count - (len(self.links_to_download) if self.links_to_download else 0) # Correct failed count calculation might be more complex if items are not removed on fail self.status_label.config(text=f"Ολοκληρώθηκαν {downloaded_count} από {initial_count} λήψεις.") messagebox.showwarning("Μερική Ολοκλήρωση", f"Ολοκληρώθηκαν {downloaded_count} από {initial_count} λήψεις.\nΕλέγξτε τη λίστα για τυχόν αποτυχίες (κόκκινο χρώμα).") elif not self.links_to_download and initial_count == 0 : self.status_label.config(text="Έτοιμο. Δεν υπάρχουν σύνδεσμοι στη λίστα.") else: self.status_label.config(text="Οι λήψεις διακόπηκαν από τον χρήστη.") self.current_download_thread = None def show_format_selection_dialog(self, video_info): dialog = tk.Toplevel(self.root) dialog.title("Επιλογή Μορφής & Ονόματος") dialog.geometry("650x480") # Slightly wider dialog.transient(self.root) dialog.grab_set() result = {} suggested_name_raw = video_info.get('title', 'ertflix_video') suggested_name = re.sub(r'[\\/*?:"<>|]', "", suggested_name_raw)[:150] # Limit length ttk.Label(dialog, text="Όνομα Αρχείου:").grid(row=0, column=0, padx=5, pady=5, sticky="w") name_entry = ttk.Entry(dialog, width=70) # Wider name_entry.insert(0, suggested_name) name_entry.grid(row=0, column=1, columnspan=2, padx=5, pady=5, sticky="ew") ttk.Label(dialog, text="Ποιότητα Βίντεο:").grid(row=1, column=0, padx=5, pady=5, sticky="w") video_formats_combo = ttk.Combobox(dialog, width=67, state="readonly") # Wider video_formats_combo.grid(row=1, column=1, columnspan=2, padx=5, pady=5, sticky="ew") video_options = [] video_map = {} default_video_selection = None highest_res_so_far = 0 for fmt in video_info.get('formats', []): if fmt.get('vcodec') != 'none' and fmt.get('vcodec') != 'unknown_video' and fmt.get('acodec') == 'none': res = fmt.get('height', 0) if not isinstance(res, int): res = 0 # Ensure res is int fps_str = f"@{int(fmt['fps'])}fps" if fmt.get('fps') and isinstance(fmt['fps'], (int, float)) else "" vbr_str = f"~{int(fmt['vbr'])}k" if fmt.get('vbr') and isinstance(fmt['vbr'], (int, float)) else "" ext = fmt.get('ext', 'N/A') format_note = f" ({fmt.get('format_note', '')})" if fmt.get('format_note') else "" display = f"{fmt.get('format_id')} - {res}p{fps_str}{format_note} ({fmt.get('vcodec','N/A')}, {ext}, {vbr_str})" video_options.append(display) video_map[display] = fmt['format_id'] # Logic for default selection (best or last used) if self.last_video_quality_id == fmt['format_id']: default_video_selection = display elif default_video_selection is None and res > highest_res_so_far: # Basic "best" highest_res_so_far = res default_video_selection = display video_formats_combo['values'] = sorted(video_options, key=lambda x: int(re.search(r'- (\d+)p', x).group(1)) if re.search(r'- (\d+)p', x) else 0, reverse=True) # Sort by resolution if default_video_selection and default_video_selection in video_formats_combo['values']: video_formats_combo.set(default_video_selection) elif video_formats_combo['values']: video_formats_combo.current(0) ttk.Label(dialog, text="Ποιότητα Ήχου:").grid(row=2, column=0, padx=5, pady=5, sticky="w") audio_formats_combo = ttk.Combobox(dialog, width=67, state="readonly") # Wider audio_formats_combo.grid(row=2, column=1, columnspan=2, padx=5, pady=5, sticky="ew") audio_options = [] audio_map = {} default_audio_selection = None highest_abr_so_far = 0 for fmt in video_info.get('formats', []): if fmt.get('acodec') != 'none' and fmt.get('acodec') != 'unknown_audio' and fmt.get('vcodec') == 'none': abr = fmt.get('abr', 0) if not isinstance(abr, (int,float)): abr = 0 # Ensure abr is numeric ext = fmt.get('ext', 'N/A') display = f"{fmt.get('format_id')} - {int(abr)}k ({fmt.get('acodec', 'N/A')}, {ext})" audio_options.append(display) audio_map[display] = fmt['format_id'] if self.last_audio_quality_id == fmt['format_id']: default_audio_selection = display elif default_audio_selection is None and abr > highest_abr_so_far: # Basic "best" highest_abr_so_far = abr default_audio_selection = display audio_formats_combo['values'] = sorted(audio_options, key=lambda x: int(re.search(r'- (\d+)k', x).group(1)) if re.search(r'- (\d+)k', x) else 0, reverse=True) # Sort by bitrate if default_audio_selection and default_audio_selection in audio_formats_combo['values']: audio_formats_combo.set(default_audio_selection) elif audio_formats_combo['values']: audio_formats_combo.current(0) ttk.Label(dialog, text="Φάκελος Αποθήκευσης:").grid(row=3, column=0, padx=5, pady=5, sticky="w") path_entry = ttk.Entry(dialog, width=60) # Wider path_entry.insert(0, self.last_save_directory) path_entry.grid(row=3, column=1, padx=5, pady=5, sticky="ew") def browse_path(): directory = filedialog.askdirectory(initialdir=path_entry.get() or self.last_save_directory, title="Επιλογή Φακέλου Αποθήκευσης") if directory: path_entry.delete(0, tk.END) path_entry.insert(0, directory) browse_button = ttk.Button(dialog, text="...", command=browse_path, width=3) browse_button.grid(row=3, column=2, padx=5, pady=5, sticky="w") dialog.grid_columnconfigure(1, weight=1) button_frame = ttk.Frame(dialog) button_frame.grid(row=4, column=0, columnspan=3, pady=10) def on_ok(): if not name_entry.get().strip(): messagebox.showerror("Λείπει Όνομα", "Το όνομα αρχείου δεν μπορεί να είναι κενό.", parent=dialog) return if not video_formats_combo.get() or not audio_formats_combo.get(): messagebox.showerror("Λείπει Επιλογή", "Πρέπει να επιλέξετε ποιότητα βίντεο και ήχου.", parent=dialog) return if not path_entry.get().strip() or not os.path.isdir(path_entry.get().strip()): messagebox.showerror("Λάθος Φάκελος", "Ο φάκελος αποθήκευσης δεν είναι έγκυρος.", parent=dialog) return result["name"] = name_entry.get().strip() result["video_id"] = video_map.get(video_formats_combo.get()) # Use .get() for safety result["audio_id"] = audio_map.get(audio_formats_combo.get()) # Use .get() for safety result["path"] = path_entry.get().strip() if not result["video_id"] or not result["audio_id"]: messagebox.showerror("Σφάλμα Επιλογής", "Προέκυψε σφάλμα με την επιλογή μορφής. Δοκιμάστε ξανά.", parent=dialog) return dialog.destroy() def on_cancel(): dialog.destroy() ok_button = ttk.Button(button_frame, text="OK", command=on_ok) ok_button.pack(side=tk.LEFT, padx=10) cancel_button = ttk.Button(button_frame, text="Άκυρο", command=on_cancel) cancel_button.pack(side=tk.LEFT, padx=10) dialog.protocol("WM_DELETE_WINDOW", on_cancel) self.root.wait_window(dialog) return result if __name__ == "__main__": if not os.path.exists(YT_DLP_PATH): import shutil if shutil.which("yt-dlp") or shutil.which("yt-dlp.exe"): YT_DLP_PATH = "yt-dlp" else: root_check = tk.Tk() root_check.withdraw() messagebox.showerror("Σφάλμα Κρίσιμο", f"Το {YT_DLP_PATH} δεν βρέθηκε!\nΠαρακαλώ τοποθετήστε το yt-dlp.exe στον ίδιο φάκελο με την εφαρμογή ή προσθέστε το στο PATH του συστήματος.") root_check.destroy() exit(1) root = tk.Tk() app = ErtflixDownloaderApp(root) root.mainloop()
-
17-05-25, 23:09 Απάντηση: Πως κατεβάζουμε(πλέον) από το Ertflix.gr ντοκυμαντέρ & σειρές για παρακολούθηση offline? #307
-
17-05-25, 23:17 Απάντηση: Πως κατεβάζουμε(πλέον) από το Ertflix.gr ντοκυμαντέρ & σειρές για παρακολούθηση offline? #308
@yyy χαίρομαι να είσαι καί εσύ καλά.
-
22-05-25, 16:39 Απάντηση: Πως κατεβάζουμε(πλέον) από το Ertflix.gr ντοκυμαντέρ & σειρές για παρακολούθηση offline? #309
Μηπως υπαρχει m3u8 για το μεγα τσανελ?
Bookmarks