Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

將下載功能交給yt-dlp處理的可能性 #20

Closed
s881116s opened this issue Jan 26, 2022 · 5 comments
Closed

將下載功能交給yt-dlp處理的可能性 #20

s881116s opened this issue Jan 26, 2022 · 5 comments

Comments

@s881116s
Copy link

大大你好,感謝分享這個工具。
我最近在研究yt-dlp的時候,發現它還可以下載m3u8的檔案,並且可以搭配aria2c達到更加星爆的速度。
然後就想起了這個專案,用我那超破爛的技術力暴力修改了一下myself方法。

    @classmethod
    def download_animate_simple_example(cls, url, ep, j):
        """
        這是一個下載動漫簡單範例,肯定會發生請求錯誤,請自己修改邏輯判斷。
        :return:
        """
        # 取得白色相簿2的基本資訊。
        animate_info = cls.animate_total_info(url=url)
        ep = ep-1
        # 我要下載第一集,所以先拿出第一集的資料。
        episode1_info = animate_info['video'][ep]

        # 拿 vpx 資料。
        vpx_json = cls.get_vpx_json(url=episode1_info['url'])

        # 整理 host 順序,我個人猜測 weight 越高的越好。
        host = sorted(vpx_json['host'], key=lambda x: x.get('weight'), reverse=True)

        # 將 weight 最高的 host 與 720p m3u8網址拿出來,組成完整 m3u8 網址。
        m3u8_url = f"{host[0]['host']}{vpx_json['video']['720p']}"
        if aria2c == True:
            cmd = f'yt-dlp --output "%(title)s.%(ext)s" --downloader aria2c --downloader-args aria2c:"-j {j}" {m3u8_url}'
        else:
            cmd = f'yt-dlp --output "%(title)s.%(ext)s" {m3u8_url}'
        print('準備下載   ' + str(animate_info['name']) + ' ' + str(animate_info['video'][ep]['name']))
        subprocess.call(cmd, shell=True)
        os.rename('720p.mp4', str(animate_info['name']) + ' ' + str(animate_info['video'][ep]['name']) + '.mp4')
        old_path = './' + str(animate_info['name']) + ' ' + str(animate_info['video'][ep]['name']) + '.mp4' 
        new_path = './' + str(animate_info['name']) + '/' + str(animate_info['name']) + ' ' + str(animate_info['video'][ep]['name']) + '.mp4'
        try:
            os.rename(old_path, new_path)
        except:
            os.mkdir('./' + str(animate_info['name']))
            os.rename(old_path, new_path)

def hello(DL_all, aria2c):
    print('MyselfAnimeDownloader ver 0.1')
    print('============================================')
    if DL_all == True:
        print('下載模式:全集')
    else:
        print('下載模式:單集')
    if aria2c == True:
        print('請務必確認aria2c已經啟動,否則將無法下載')
    print('============================================')

if __name__ == "__main__":
    config = configparser.ConfigParser()
    config.read('config.ini')
    DL_mode = config['DL_MODE'].getboolean('all')
    aria2c = config['DL_MODE'].getboolean('aria2c')
    if aria2c == True:
        x = config['aria2c'].getint('x')
        j = config['aria2c'].getint('j')
    hello(DL_all=DL_mode, aria2c=aria2c)
    id = input('id? ')
    ep = int(input('episode? '))
    url= 'https://myself-bbs.com/thread-' + id + '-1-1.html'
    Myself.animate_total_info(url=url)
    Myself.download_animate_simple_example(url=url, ep=ep , j=j)

只要調高aria2c下載的線程數,就能幾乎滿速下載,應該也不會佔用太多記憶體。不過以我的技術力最多只能改到這裡,GUI的部分就很有困難了,希望大大有空可以評估一下這種做法的可行性。
謝謝。

@hgalytoby
Copy link
Owner

大大你好,感謝分享這個工具。 我最近在研究yt-dlp的時候,發現它還可以下載m3u8的檔案,並且可以搭配aria2c達到更加星爆的速度。 然後就想起了這個專案,用我那超破爛的技術力暴力修改了一下myself方法。

謝謝。

只要調高aria2c下載的線程數,就能幾乎滿速下載,應該也不會佔用太多記憶體。不過以我的技術力最多只能改到這裡,GUI的部分就很有困難了,希望大大有空可以評估一下這種做法的可行性。 謝謝。

最近我也在研究 yt-dlp,我沒想過能拿來下載 m3u8 的檔案呢,學到了!

我看你的程式碼是用 cmd 下指令下載 m3u8,這樣我沒辦法確認下載進度。

yt-dlp 也有不用 cmd 的方式,而是使用程式碼的方式下載影片,但我不知道用下載 m3u8 有沒有回調函數能讓我能計算下載進度。

想要下載快一點就是多開一點 Thread ,但是多開 Thread 會變成在攻擊伺服器。

Myself 網站是一個很棒的網站,我不希望網站出事情,所以我的程式星爆限制 10 Thread。

剛剛覺得 aria2c 很眼熟,Google 看了一下發現是以前我用來下載百度的東西ㄏㄏ。

我很好奇 cmd = f'yt-dlp --output "%(title)s.%(ext)s" --downloader aria2c --downloader-args aria2c:"-j {j}" {m3u8_url}'

這一段指令是中間會將任務丟給 aria2c 去執行?

我沒用過指令的方式去驅動 aria2c

你能分享指令中的各個參數的意思嗎? 我很好奇。

@s881116s
Copy link
Author

是的, --downloader aria2c就是把下載交給外部下載器aria2c, --downloader-args aria2c:"-j {j}"則是aria2c下載時的參數,j 代表同時下載幾個分割的檔案,x 參數我記得是使用線程數,但後來發現它對於速度沒有顯著效果,不如一次下個數個分割檔,就沒有丟進cmd。
以我的感覺來說,一次下載3個就有滿不錯的速度了。

另外,我剛剛又再去看了一下,yt-dlp本身也支援thread下載m3u8,並且有提供下載進度,應該可以透過獲取cmd的執行內容來掌握下載進度。
就在這一段Multi-threaded fragment downloads: Download multiple fragments of m3u8/mpd videos in parallel. Use --concurrent-fragments (-N) option to set the number of threads used
但感覺內建的多線程下載不太穩定,容易被對方伺服器擋下來關閉連線,aria2c目前沒被擋過,所以要多線程大概還是只能交給它。
(不過就算沒有使用內建多線程,一般的下載速度我個人還算能接受,差不多十分鐘能下載完一集TV動畫吧。)

@hgalytoby
Copy link
Owner

hgalytoby commented Jan 27, 2022

是的, --downloader aria2c就是把下載交給外部下載器aria2c, --downloader-args aria2c:"-j {j}"則是aria2c下載時的參數,j 代表同時下載幾個分割的檔案,x 參數我記得是使用線程數,但後來發現它對於速度沒有顯著效果,不如一次下個數個分割檔,就沒有丟進cmd。 以我的感覺來說,一次下載3個就有滿不錯的速度了。

你有提到 x 參數,但我沒在 cmd 裡面發現 x,我也就不知道要在哪裡加了,是這樣 --downloader-args aria2c:"-j {j} -x {x}"?

另外,我剛剛又再去看了一下,yt-dlp本身也支援thread下載m3u8,並且有提供下載進度,應該可以透過獲取cmd的執行內容來掌握下載進度。 就在這一段Multi-threaded fragment downloads: Download multiple fragments of m3u8/mpd videos in parallel. Use --concurrent-fragments (-N) option to set the number of threads used 但感覺內建的多線程下載不太穩定,容易被對方伺服器擋下來關閉連線,aria2c目前沒被擋過,所以要多線程大概還是只能交給它。 (不過就算沒有使用內建多線程,一般的下載速度我個人還算能接受,差不多十分鐘能下載完一集TV動畫吧。)

如果說要改成用 aria2c 下載的話,看起來是可行的,GUI 會多一個額外選項像你的範例一樣 aria2c == True: or aria2c == False,做下載方式切換,所以要捕捉下載進度的話,就必須要用 subprocess 去抓 output 了對嗎?

最初我開發的時候還很菜,只會用 with opeh 'ab' 的方式, 所以當時就沒用 ffmepgyt-dlp 這類的抓 m3u8 的影片。

現在我再將此專案 GUI 改成 Web 版,所以可能不會做這個擴充 aria2c 的功能了,如果 GUI 要增加這 aria2c 的話,我會想打掉很多 code 重寫,我自己看 code 都難過了ㄏㄏ。

@s881116s
Copy link
Author

你有提到 x 參數,但我沒在 cmd 裡面發現 x,我也就不知道要在哪裡加了,是這樣 --downloader-args aria2c:"-j {j} -x {x}"?

對。

如果說要改成用 aria2c 下載的話,看起來是可行的,GUI 會多一個額外選項像你的範例一樣 aria2c == True: or aria2c == False,做下載方式切換,所以要捕捉下載進度的話,就必須要用 subprocess 去抓 output 了對嗎?

應該說,如果沒有呼叫外部下載工具的話,yt-dlp的下載功能本身會提供進度,就可以抓output。就像這樣:
image
然後應該就能用正規表示式取得%數。

但是用aria2c的話,cmd輸出會長這樣:
image
要獲取下載進度的話,只能透過 (已下載分割檔數/總分割檔數)*100 的方式計算。我的想法是偵測資料夾內已經下載的part數量,然後除以總分割檔數量來計算%數。

最初我開發的時候還很菜,只會用 with opeh 'ab' 的方式, 所以當時就沒用 ffmepg 與 yt-dlp 這類的抓 m3u8 的影片。

正因為我菜才會想用cmd暴力解決,也很省事,不然我根本無法想像要怎麼只靠with open搞多線程下載ㄏㄏ。

現在我再將此專案 GUI 改成 Web 版,所以可能不會做這個擴充 aria2c 的功能了,如果 GUI 要增加這 aria2c 的話,我會想打掉很多 code 重寫,我自己看 code 都難過了ㄏㄏ。

我也有想到專案需要可能大改,所以只是問問看可不可行而已,如果大大不打算大改,只打算維護的話,就當我沒說過吧。

@hgalytoby
Copy link
Owner

hgalytoby commented Jan 27, 2022

對。

Ok。

應該說,如果沒有呼叫外部下載工具的話,yt-dlp的下載功能本身會提供進度,就可以抓output。就像這樣: image 然後應該就能用正規表示式取得%數。

但是用aria2c的話,cmd輸出會長這樣: image 要獲取下載進度的話,只能透過 (已下載分割檔數/總分割檔數)*100 的方式計算。我的想法是偵測資料夾內已經下載的part數量,然後除以總分割檔數量來計算%數。

我拿 Youtube 當範例,應該有 callback 可以使用。

from yt_dlp import YoutubeDL


url = 'https://youtu.be/q3HALa3M1A8'

def callback(d):
    print(d['downloaded_bytes'] / d['total_bytes'] * 100, d['_percent_str'])

download_opts = {
    'progress_hooks': [callback],
}
with YoutubeDL(download_opts) as ydl:
    ydl.download([url])

最簡單的就是用你說的偵測資料夾方法。

正因為我菜才會想用cmd暴力解決,也很省事,不然我根本無法想像要怎麼只靠with open搞多線程下載ㄏㄏ。

ㄏㄏ,我 Web 版就不用with open做了。

我也有想到專案需要可能大改,所以只是問問看可不可行而已,如果大大不打算大改,只打算維護的話,就當我沒說過吧。

你說的方法肯定是可行的,但我目前只打算做維護。

因為現在我工作是做 Web 相關,所以我希望我接下來的作品都跟 Web 有關。

您提供的這個下載方式,讓我又學到了一招,感謝您的分享。

我會把這個問題至頂,如果有人想要更快就可以參考您的這個方法。

如果以後還有什麼好康的,希望您還能多多分享給我。

謝謝您。

@hgalytoby hgalytoby pinned this issue Jan 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants