PageSourceSearch

https://www.algoltek.com.tw/assets/frontend/javascript/plugins/gtut_youtube_banner_player.js

js algoltek.com.tw collected 2026-10-05 18:10:57 UTC 7,666 bytes, 216 lines download raw bytes

1class gtutYoutubeBannerPlayer {
2    constructor(selector, videoIframe, config) {
3
4        this.videoIframe = videoIframe
5        this.videoId = document.querySelector(`${selector} #${videoIframe}`).getAttribute('data-video-id');
6        this.overlay = document.querySelector(`${selector} .gtut_yt_overlay`);
7        this.player = null; // 在類別中定義播放器成員變量
8        this.youtubeSettings = {
9            videoId: this.transformVideoId(this.videoId),
10            height: '1440',
11            width: '2560',
12            useCoverImg: true,
13            autoPlay: true,
14            loop: true,
15            bleed: false,
16            playerVars: {
17                controls: 0,
18                fs: 0,
19                iv_load_policy: 3,
20                rel: 0,
21                modestbranding: 1,
22                playsinline: 1,
23            },
24            events: {
25                onReady: this.onPlayerReady,
26                onStateChange: this.onPlayerStateChange,
27            },
28        };
29        this.firstRePlayVideo = true;
30        this.firstInThisSite = sessionStorage.getItem("inThisSite");
31        if (this.firstInThisSite) {
32            this.firstRePlayVideo = false;
33        } else {
34            sessionStorage.setItem("inThisSite", true);
35        }
36        this.extendConfig = this.extendConfig.bind(this);
37        this.addCoverImg = this.addCoverImg.bind(this);
38        this.removerCoverImg = this.removerCoverImg.bind(this);
39        this.checkLoopShowControls = this.checkLoopShowControls.bind(this);
40        // Call initialization function
41        this.playerInitialized = false;
42        this.apiLoaded = false;
43        this.init(config);
44    }
45    init(config) {
46        this.youtubeSettings = this.extendConfig(this.youtubeSettings, config);
47        if (!this.youtubeSettings.loop) {
48            this.youtubeSettings.playerVars.controls = 1;
49        }
50        if (!this.apiLoaded) {
51            // 加載 YT API
52            let existingScript = document.querySelector('script[src="' + 'https://www.youtube.com/iframe_api' + '"]');
53            if (!existingScript) {
54                const tag = document.createElement('script');
55                tag.src = 'https://www.youtube.com/iframe_api';
56                const firstScriptTag = document.getElementsByTagName('script')[0];
57                firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
58            }
59
60            // 标记 API 已加载
61            this.apiLoaded = true;
62        }
63
64        // console.log('等待');
65                // 等待 YT API 加載完成
66        if (window.onYouTubeIframeAPIReady) {
67            const oldCallback = window.onYouTubeIframeAPIReady;
68            window.onYouTubeIframeAPIReady = () => {
69                oldCallback();
70                this.initPlayer();
71            }
72            this.initPlayer();
73            // console.log('yt api ready');
74        } else {
75
76            window.onYouTubeIframeAPIReady = () => {
77                this.initPlayer();
78            }
79
80                // console.log(' else');
81        }
82        // console.log('init');
83
84    }
85
86    initPlayer() {
87        // console.log('initPlayer');
88            if (!this.playerInitialized) {
89                const hiddenProperty = 'hidden' in document
90                ? 'hidden'
91                : 'webkitHidden' in document
92                    ? 'webkitHidden'
93                    : 'mozHidden' in document
94                        ? 'mozHidden'
95                        : null;
96            const visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange');
97            let leaveTime;
98            let backTime;
99            const onVisibilityChange = () => {
100                if (!document[hiddenProperty]) {
101                    backTime = Date.now();
102                    if (leaveTime == undefined || backTime > leaveTime + 600000) {
103                        location.reload();
104                    }
105                } else {
106                    leaveTime = Date.now();
107                }
108            };
109                document.addEventListener(visibilityChangeEvent, onVisibilityChange);
110            const that = this
111            function checkYTPlayer() {
112                if (typeof YT !== 'undefined') {
113                    // YT exists, create the player
114                    that.player = new YT.Player(`${that.videoIframe}`, that.youtubeSettings);
115                } else {
116                    // YT does not exist yet, check again after 200 milliseconds
117                    setTimeout(checkYTPlayer, 300);
118                }
119            }
120
121            // 開始檢查 YT Player
122            checkYTPlayer();
123            if (this.youtubeSettings.useCoverImg) {
124                this.addCoverImg(this.youtubeSettings.useCoverImg);
125            }
126            if (this.youtubeSettings.bleed && this.youtubeSettings.autoPlay && this.youtubeSettings.loop) {
127                document.querySelector(`#${this.videoIframe}`).classList.add('big_size');
128            }
129            this.playerInitialized = true;
130            // console.log('playerInitialized');
131        }
132    }
133
134    transformVideoId(id) {
135        const youtubeVideoIdLength = 11;
136        let newId = '';
137        if (id.length <= youtubeVideoIdLength) {
138            return id;
139        }
140        if (id.indexOf('watch?v=') > 0) {
141            newId = id.substr(id.indexOf('watch?v=') + 8, youtubeVideoIdLength);
142        } else if (id.indexOf('youtu.be/') > 0) {
143            newId = id.substr(id.indexOf('youtu.be/') + 9, youtubeVideoIdLength);
144        } else if (id.indexOf('/embed/') > 0) {
145            newId = id.substr(id.indexOf('/embed/') + 7, youtubeVideoIdLength);
146        } else {
147            newId = id.substr(id.lastIndexOf('/') + 1, id.length);
148            if (newId.length > youtubeVideoIdLength) {
149                newId = newId.substr(0, youtubeVideoIdLength);
150            }
151        }
152        return newId;
153    }
154
155    addCoverImg(src) {
156        let imgUrl;
157        if (src === true) {
158            imgUrl = `https://img.youtube.com/vi/${this.youtubeSettings.videoId}/maxresdefault.jpg`;
159            const customCoverImg = this.overlay.getAttribute('data-coverimg');
160            if (customCoverImg) {
161                imgUrl = customCoverImg;
162            }
163        } else {
164            imgUrl = src;
165        }
166
167        this.overlay.style.backgroundImage = `url(${imgUrl})`;
168    }
169
170    removerCoverImg() {
171        this.overlay.style.opacity = 0;
172    }
173
174    extendConfig(a, b) {
175        for (const key in b) if (b.hasOwnProperty(key)) a[key] = b[key];
176        return a;
177    }
178
179    checkLoopShowControls= () => {
180        if (!this.youtubeSettings.loop) {
181            this.overlay.style.pointerEvents = 'none';
182        }
183    }
184
185
186    onPlayerReady = (e) => {
187        // console.log('onPlayerReady');
188        if (this.youtubeSettings.useCoverImg) {
189            this.removerCoverImg();
190        }
191        if (this.youtubeSettings.autoPlay) {
192            e.target.mute().playVideo();
193        } else {
194            this.overlay.style.cursor = 'pointer';
195            this.overlay.addEventListener('click', () => {
196                e.target.playVideo();
197                this.checkLoopShowControls();
198            });
199        }
200    }
201
202    onPlayerStateChange = (event) => {
203        if (event.data === 0 && this.youtubeSettings.loop) {
204            if (this.firstRePlayVideo) {
205                this.player.loadVideoById(this.transformVideoId(this.videoId));
206                this.firstRePlayVideo = false;
207            } else {
208                event.target.playVideo();
209            }
210        }
211        if (event.data === 0 && !this.youtubeSettings.loop) {
212            this.checkLoopShowControls();
213        }
214    }
215}
216

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.