PageSourceSearch

https://gall.dcinside.com/_js/ad_audit.js?v=2605081820

js dcinside.com collected 2026-09-24 08:57:49 UTC 8,387 bytes, 309 lines download raw bytes

1// ad_audit.js
2
3$(function () {
4
5    const SAMPLE_RATE = 0.001; // 0.1 = 10%, 0.01 = 1%
6    const USE_DAILY_LIMIT = true;
7
8    const LOG_URL = 'https://gall.dcinside.com/dcad/ad_audit_log';
9    const AUDIT_KEY = 'DC_AUDIT_KEY_2026';
10
11    const FIRST_WAIT_TIME = 3000;
12    const RETRY_WAIT_TIME = 5000;
13
14    const today = new Date().toISOString().slice(0, 10);
15    const dailyKey = 'ad_audit_checked_' + location.hostname + '_' + today;
16
17    if (USE_DAILY_LIMIT && localStorage.getItem(dailyKey)) {
18        return;
19    }
20
21    if (Math.random() > SAMPLE_RATE) {
22        return;
23    }
24
25    if (USE_DAILY_LIMIT) {
26        localStorage.setItem(dailyKey, 'Y');
27    }
28
29    const AD_CONFIGS = [
30        {
31            ad_type: 'kakao',
32            script_keyword: 'ba.min.js',
33            selector: '.kakao_ad_area',
34            unit_attr: 'data-ad-unit',
35            width_attr: 'data-ad-width',
36            height_attr: 'data-ad-height',
37            require_unit: true
38        },
39        {
40            ad_type: 'google_adsense_old',
41            script_keyword: 'show_ads.js',
42            selector: '.google_ad_area',
43            unit_attr: 'data-ad-unit',
44            width_attr: 'data-ad-width',
45            height_attr: 'data-ad-height',
46            require_unit: true
47        },
48        {
49            ad_type: 'google_adsense_new',
50            script_keyword: 'adsbygoogle',
51            selector: '.adsbygoogle',
52            unit_attr: 'data-ad-slot',
53            width_attr: null,
54            height_attr: null,
55            require_unit: true
56        },
57        {
58            ad_type: 'netinsight_criteo',
59            script_keyword: 'ad.xc.netinsight.co.kr',
60            selector: 'div[id^="criteo-"]',
61            unit_attr: 'id',
62            width_attr: null,
63            height_attr: null,
64            require_unit: true
65        },
66        {
67            ad_type: 'adnmore_toast',
68            script_keyword: 'adnmore.co.kr',
69            selector: 'div[id^="foin_"]',
70            unit_attr: 'id',
71            width_attr: null,
72            height_attr: null,
73            require_unit: true
74        }
75    ];
76
77    const getScriptInfo = (keyword) => {
78        const result = {
79            exists: false,
80            src: ''
81        };
82
83        $('script').each(function () {
84            const src = $(this).attr('src') || '';
85
86            if (src.indexOf(keyword) !== -1) {
87                result.exists = true;
88                result.src = src;
89                return false;
90            }
91        });
92
93        return result;
94    };
95
96    const getAdSize = ($ad, config) => {
97        let width = 0;
98        let height = 0;
99
100        if (config.width_attr) {
101            width = parseInt($ad.attr(config.width_attr), 10) || 0;
102        } else {
103            width = $ad.width() || parseInt($ad.attr('width'), 10) || 0;
104        }
105
106        if (config.height_attr) {
107            height = parseInt($ad.attr(config.height_attr), 10) || 0;
108        } else {
109            height = $ad.height() || parseInt($ad.attr('height'), 10) || 0;
110        }
111
112        return {
113            width,
114            height
115        };
116    };
117
118    const getVisibleIframe = ($ad) => {
119        return $ad.find('iframe').filter(function () {
120            const $iframe = $(this);
121
122            const width =
123                $iframe.width() ||
124                parseInt($iframe.attr('width'), 10) ||
125                0;
126
127            const height =
128                $iframe.height() ||
129                parseInt($iframe.attr('height'), 10) ||
130                0;
131
132            if (width <= 0 || height <= 0) {
133                return false;
134            }
135
136            if ($iframe.css('display') === 'none') {
137                return false;
138            }
139
140            return true;
141        });
142    };
143
144    const sendAuditLog = (data) => {
145        $.ajax({
146            url: LOG_URL,
147            type: 'POST',
148            dataType: 'json',
149            data,
150            timeout: 3000,
151            crossDomain: true,
152            error: () => {
153                console.log('[AD AUDIT] 로그 저장 실패');
154            }
155        });
156    };
157
158    const processAudit = (config, scriptInfo, $ad, index, retry) => {
159
160        const adUnit = config.unit_attr
161            ? ($ad.attr(config.unit_attr) || '')
162            : '';
163
164        // ad_unit 없는 내부 DOM은 저장하지 않음
165        if (config.require_unit && !adUnit) {
166            return;
167        }
168
169        const adVisible = $ad.is(':visible') ? 'Y' : 'N';
170
171        const $iframe = getVisibleIframe($ad);
172        const iframeExists = $iframe.length > 0;
173
174        const adSize = getAdSize($ad, config);
175
176        const iframeWidth = iframeExists
177            ? (
178                $iframe.first().width() ||
179                parseInt($iframe.first().attr('width'), 10) ||
180                0
181            )
182            : 0;
183
184        const iframeHeight = iframeExists
185            ? (
186                $iframe.first().height() ||
187                parseInt($iframe.first().attr('height'), 10) ||
188                0
189            )
190            : 0;
191
192        const adStatus = $ad.attr('data-ad-status') || '';
193
194        let auditStatus = 'success';
195
196        if (!scriptInfo.exists) {
197            auditStatus = 'script_fail';
198        } else if (!iframeExists) {
199            auditStatus = 'render_fail';
200        } else if (adVisible === 'N') {
201            auditStatus = 'hidden';
202        }
203
204        if (auditStatus === 'render_fail' && retry === false) {
205            console.log('[AD AUDIT RETRY]', config.ad_type);
206
207            setTimeout(() => {
208                processAudit(
209                    config,
210                    scriptInfo,
211                    $ad,
212                    index,
213                    true
214                );
215            }, RETRY_WAIT_TIME);
216
217            return;
218        }
219
220        const result = {
221            audit_key: AUDIT_KEY,
222
223            ad_type: config.ad_type,
224            domain: location.hostname,
225            page_url: location.href,
226            user_agent: navigator.userAgent,
227
228            ad_index: index,
229            ad_unit: adUnit,
230
231            ad_width: adSize.width,
232            ad_height: adSize.height,
233
234            script_exists: scriptInfo.exists ? 'Y' : 'N',
235            script_src: scriptInfo.src,
236
237            iframe_exists: iframeExists ? 'Y' : 'N',
238            iframe_width: iframeWidth,
239            iframe_height: iframeHeight,
240
241            ad_status: adStatus,
242            ad_visible: adVisible,
243            audit_status: auditStatus
244        };
245
246        console.log('[AD AUDIT]', result);
247
248        sendAuditLog(result);
249    };
250
251    setTimeout(() => {
252
253        $.each(AD_CONFIGS, (_, config) => {
254
255            const scriptInfo = getScriptInfo(config.script_keyword);
256            const $targets = $(config.selector);
257
258            if ($targets.length <= 0) {
259                const result = {
260                    audit_key: AUDIT_KEY,
261
262                    ad_type: config.ad_type,
263                    domain: location.hostname,
264                    page_url: location.href,
265                    user_agent: navigator.userAgent,
266
267                    ad_index: 0,
268                    ad_unit: '',
269
270                    ad_width: 0,
271                    ad_height: 0,
272
273                    script_exists: scriptInfo.exists ? 'Y' : 'N',
274                    script_src: scriptInfo.src,
275
276                    iframe_exists: 'N',
277                    iframe_width: 0,
278                    iframe_height: 0,
279
280                    ad_status: '',
281                    ad_visible: 'N',
282
283                    audit_status: scriptInfo.exists
284                        ? 'selector_fail'
285                        : 'script_fail'
286                };
287
288                console.log('[AD AUDIT FAIL]', result);
289
290                sendAuditLog(result);
291
292                return;
293            }
294
295            $targets.each(function (index) {
296                processAudit(
297                    config,
298                    scriptInfo,
299                    $(this),
300                    index,
301                    false
302                );
303            });
304
305        });
306
307    }, FIRST_WAIT_TIME);
308
309});

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.