אוטומציה לטלוויזיה

אוטומציה לטלוויזיה

קראתי לא מזמן כאן, על בחור שכל פעולה הכי קטנה שהוא היה צריך לבצע – כתב בשבילה סקריפט אוטומציה. הרבה פעמים יש (לי) את ההתלבטות מהו הגבול, מתי זה לא נורא לחזור על אותה פעולה – פשוטה בדרך כלל – שוב ושוב, ומתי זה כבר מוגזם ואפשרצריך לכתוב סקריפט שיעשה את זה במקומך.

דיסקליימר: אין בשורות הבאות שום עידוד או תמיכה בהורדות לא חוקיות וכדו', אלא מדובר בתרגיל תאורטי לחלוטין, שיכול לשמש לצרכים נוספים.
אחרי שכתבתי את זה, אפשר להתחיל.

נוחות

הורדת את הסדרה האהובה עליך. נניח יש בה 12 פרקים לעונה. הורדת גם קובץ zip מאתר הכתוביות האהוב עליך, שמכיל כתוביות לכל הפרקים בגירסאות שונות ומשונות. בדרך כלל זה נראה משהו כזה:

902f4-match_before2

וכן הלאה. לא הכי סימפטי לעבור על כל התיקיות, לחלץ את קבצי הסרטים משם, ואז לעבור על הכתוביות ולמצוא את הגירסא המתאימה לכל וידאו, עד שזה יראה כך (כשהקבצים מסודרים ככה, הנגן יודע אוטומטית איזו כתובית לטעון):

145f5-match_after

 

קוד

פעולה ראשונה שצריך לעשות, היא לעבור על כל הקבצים בכל התתי תיקיות (כולל בתוך קבצי zip) וליצור שתי רשימות: קבצי וידאו, וכתוביות. פעולה שניה תהיה להתאים אחד לשני.

נסתכל על מתודת bash הזו:

function getSubfiles {
    for x in "$1"/* ; do
        if [[ "$x" =~ \.srt$ ]]; then
            subs+=("$x")
        fi
        if [[ "$x" =~ \.mp4$|\.avi$|\.mkv$ ]]; then
            videos+=("$x")
        fi
            if [ -d "$x" ]; then
            getSubfiles $x
        fi
        if [[ "$x" =~ \.zip$ ]]; then
            echo "ZIP file!"
            dirName=${x%.*}
            echo "dirName: $dirName"
            unzip -o $x -d $dirName
            rm $x
            getSubfiles $dirName
        fi
    done
}

זו פונקציה רקורסיבית, שמקבלת בתור פרמטר את התיקיה עליה לרוץ. במעבר על רשימת הקבצים, אם מדובר בכתובית (קובץ srt) נשמור את הנתיב לקובץ במערך subs, אם מדובר בקובץ וידאו נשמור את הנתיב במערך videos.

אם מדובר בתיקיה – הפונקציה תקרא לעצמה עם הנתיב של התיקיה הזו כפרמטר. אם מדובר בקובץ zip, נחלץ מתוכו את הקבצים לתיקיה בעלת אותו השם – והפונקציה תקרא לעצמה עם התיקיה החדשה כפרמטר.עכשיו נכתוב מתודה שמקבלת כפרמטר את מספר העונה, הפרק והגירסא הדרושה – ומחזירה כתובית מתאימה:

function findSub {
    season=$1
    episode=$2
    version=$3
    for sub in "${subs[@]}" ; do
        subLowerCase=$(toLowerCase $sub)
        if [[ $sub =~ $season[Eex]$episode ]] && [[ $subLowerCase =~ $version ]]; then
            echo $sub
            break
        fi 
    done   
}

כדי להיות בטוחים שהשוואת המחרוזות (strings) פועלת כשורה, ולא ניפול על בעיות של case sensitive, תמיד נהפוך את כל התווים ל- lower case, בעזרת הפונקציה הזו:

function toLowerCase {
    echo "$1" | tr '[:upper:]' '[:lower:]'
}

מה שנשאר לעשות, אחרי שהפעלנו את הפונקציה שממיינת את כל הקבצים לשני מערכים, זה לרוץ על מערך קבצי הסרטים, ולמצוא עבור כל סרט את הכתובית המתאימה לו:

echo "Found ${#videos[@]} videos, ${#subs[@]} subtitles"
echo "Starting the matching..."
counter=0
for vid in "${videos[@]}" ; do
    echo "video name: ${vid##*/}"
    vidLower=$(toLowerCase $vid)
    version=''
    if [[ "$vidLower" =~ lol|evolve|killers|asap|avs|fum|batv|fleet|sva|dimension|skgtv|turbo ]]; then
        version=${BASH_REMATCH[0]}
    fi
    if [[ $vid =~ [Ss][0-9]{2}([Ee][0-9]{2})+ ]]; then
        matched=${BASH_REMATCH[0]}
        season=${matched:1:2}
        episode=${matched:4:2}
    elif [[ $vid =~ [0-9]{3} ]]; then
        matched=${BASH_REMATCH[0]}
        season=${matched:0:1}
        episode=${matched:1:2}
        matched=${season}E${episode}
    fi
 
    if [ -z "$season" ] || [ -z "$episode" ]; then
        echo "Couldn't find season or episode for this video."
        continue
    fi
    fileType=${vid##*.}
    name=${vid%?$matched*}
    name=${name##*/}
    #echo "show name: $name season: $((10#${season})) episode $episode version: $version type: $fileType"
 
    sub=$(findSub $((10#${season})) $episode $version)
    if [ -z "$sub" ]; then
        echo "Didn't find sub"
    else   
        echo "Sub found: ${sub##*/}"
        newName="${TARGET_DIR}/${name}.$matched-${version}"
        if ! [ -e $newName.$fileType ]; then
            mv $vid $newName.$fileType
        fi
        if ! [ -e $newName.srt ]; then
            mv $sub $newName.srt
        fi
        counter=$((counter + 1))
    fi
done

מכל שם של קובץ וידאו נמצא את מספר פרק, עונה וגירסא, וכך נשלח את זה לפונקציה שמוצאת את הכתובית.

שימו לב שהנחתי כאן כמה דברים. א. רק שני פורמטים שונים בהם משתמשים כדי לציין מספר פרק ועונה. אפשר להוסיף עוד באותה הדרך. ב. ייתן ואפשר להוסיף עוד גירסאות, אני הוספתי את אלו שאני מכיר.

סיכום

אפשר למצוא את הסקריפט במלואו כאן. הוא יעבוד טוב בדרך כלל, אך במקרים מסויימים ייתכן וצריך יהיה להתאים אותו קצת. לכן כדאי להבין מה כתוב בו ולא רק להריץ.

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *