File size: 3,639 Bytes
6f54888
3ae777b
f2bee8a
 
 
 
 
 
3ae777b
f2bee8a
 
 
 
 
3ae777b
f2bee8a
 
 
 
 
 
3ae777b
f2bee8a
 
 
 
 
 
 
 
 
 
 
3ae777b
f2bee8a
 
 
 
 
 
 
 
 
 
0ebf77c
3ae777b
f2bee8a
0ebf77c
04fa2df
0427cbe
0ebf77c
 
04fa2df
f2bee8a
 
 
 
 
 
 
 
 
 
9269047
f2bee8a
 
 
 
 
9269047
f2bee8a
 
 
 
db39eac
f2bee8a
 
 
 
 
 
 
 
 
 
04fa2df
db39eac
f2bee8a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

// グローバルな進行状況管理変数
let total = 0;
let complete = 0;
let state = 0;
let currentProgress = 0;
let progressHandler = (state, progress, complete, total) => {};

// 進行状況ハンドラを設定する関数
export const setProgressHandler = newHandler => {
    progressHandler = newHandler;
    progressHandler(state, currentProgress, complete, total);
};

// 進行状況更新をキューに入れる関数
const queueProgressHandlerUpdate = () => {
    if (progressHandlerTimeout === null) {
        progressHandlerTimeout = requestAnimationFrame(fireProgressHandler);
    }
};

// 進行状況を更新する関数
const setProgress = progress => {
    if (progress < 0) {
        progress = 0;
    }
    if (progress > 1) {
        progress = 1;
    }
    currentProgress = progress;
    queueProgressHandlerUpdate();
};

// ステータスを設定する関数
const setState = newState => {
    if (state === newState) {
        return;
    }
    state = newState;
    complete = 0;
    total = 0;
    setProgress(0);
};

// 進行状況を管理する関数
const fetchWithProgress = url => {
    setState(1);
    
    // 使用するCORSプロキシURL
    const proxyUrl = `https://public-soiz1-cors-proxy.hf.space/?url=` + encodeURIComponent(url);  // ここで公開されているプロキシを使用
    //const proxyUrl = `https://cors-anywhere.herokuapp.com/` + encodeURIComponent(url);
    // const proxyUrl = `https://cors-proxy.htmldriven.com/?url=` + encodeURIComponent(url); // 別のプロキシURLを使いたい場合はこちらを使用
    // const proxyUrl = `https://api.allorigins.win/raw?url=` + encodeURIComponent(url); // 別のプロキシURLを使いたい場合はこちらを使用    
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.responseType = 'blob';
        xhr.onload = () => {
            resolve(new Response(xhr.response, {
                status: xhr.status,
                statusText: xhr.statusText
            }));
        };
        xhr.onloadend = () => setProgress(1);
        xhr.onerror = () => reject(new Error('[tw-progress-monitor] xhr failed with status ' + xhr.status));
        xhr.onprogress = e => {
            if (e.lengthComputable) {
                setProgress(e.loaded / e.total);
            }
        };
        xhr.open('GET', proxyUrl);
        xhr.send();
    });
};

// fetchのオーバーライド
const originalFetch = window.fetch;
window.fetch = (url, opts) => {
    const isGET = typeof opts === 'object' && opts && opts.method === 'GET';
    const isProjectURL = typeof url === 'string' && /^https:\/\/projects\.scratch\.mit\.edu\/\d+$/.test(url);
    if (isGET && isProjectURL) {
        return fetchWithProgress(url);
    }
    return originalFetch(url, opts);
};


// Web Workerのメッセージ処理
const handleWorkerMessage = e => {
    const data = e.data;
    if (Array.isArray(data)) {
        complete += data.length;
        setProgress(complete / total);
    }
};

if (window.Worker) {
    let downloadWorker = null;
    const originalPostMessage = window.Worker.prototype.postMessage;
    window.Worker.prototype.postMessage = function (message) {
        if (downloadWorker === null) {
            if (message && message.url && message.id && message.options) {
                downloadWorker = this;
                downloadWorker.addEventListener('message', handleWorkerMessage);
            }
        }
        if (downloadWorker === this) {
            setState(2);
            total++;
        }
        originalPostMessage.call(this, message);
    };
}