1 2<!DOCTYPE html> 3<html lang="en"> 4<head> 5 <meta charset="utf-8" /> 6 <!-- Google Tag Manager -->
7<script>
vendor: 359 bytes, lines 7-11
7(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 8 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 9 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 10 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 11 })(window,document,'script','dataLayer','
11GTM-N8PRK68K
vendor: 3 bytes, line 11
11');
11</script>
11 12<!-- End Google Tag Manager --> <meta http-equiv="content-language" content="en" /> 13 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 14 <title>Worldstarhiphop: Breaking News | Music Videos | Entertainment News | Hip Hop News</title> 15 <link href="https://worldstar.com/signup-options" rel="canonical" /> 16 <meta name="description" content="WorldstarHipHop is home to everything entertainment & hip hop. The #1 urban outlet responsible for breaking the latest urban news!"> 17 <!-- Datadog initialization --> 18
18<script type="text/javascript" src="https://www.datadoghq-browser-agent.com/datadog-logs-v4.js" crossorigin="anonymous"></script>
vendor: 1 bytes, line 18
18
19<script> 20 window.DD_LOGS && 21 DD_LOGS.init({ 22 clientToken: 'pub82afa1d2b2f8f61681f12acc743f0ad0', 23 24 /* datadog's site used by our organization */ 25 site: 'us5.datadoghq.com', 26 27 service: 'web-legacy', 28 29 /* forward console.error logs, uncaught exceptions and network errors to Datadog. */ 30 forwardErrorsToLogs: true, 31 32 /* percentage of sessions to track: 100 for all, 0 for none. Only tracked sessions send logs. */ 33 sampleRate: 1, 34 }); 35 36 // set minimum logging level, error for now 37 window.DD_LOGS && DD_LOGS.logger.setLevel('error'); 38 39 // send logs to console and datadog (https://docs.datadoghq.com/logs/log_collection/javascript/) 40 window.DD_LOGS && DD_LOGS.logger.setHandler('http') 41</script>
41 42 <!-- JQuery script --> 43
43<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
43 44 <!-- For some reason jquery seems not to be loaded at times, this is the purpose of the hack below --> 45
45<script type="text/javascript"> 46 window.jQuery || document.write('
46<script src="/videos/js/jquery-3.5.1.min.js"><\/script>') 47 </script>
47 48
48<script src="https://code.jquery.com/jquery-migrate-3.3.2.min.js" integrity="sha256-Ap4KLoCf1rXb52q+i3p0k2vjBsmownyBTE1EqlRiMwA=" crossorigin="anonymous"></script>
48 49 50
50<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/cure53/DOMPurify@main/dist/purify.min.js"></script>
50 51
51<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/uuid@latest/dist/umd/uuid.min.js"></script>
51 52
52<script type="text/javascript" src="/videos/js/utils.js"></script>
52 53 54 <!-- Bootstrap css --> 55 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> 56 57 <!-- css --> 58 <link media="all" rel="stylesheet" href="/videos/assets/css/fonts.css"> 59 <link media="all" rel="stylesheet" href="/videos/assets/css/all.css"> 60 <link media="all" rel="stylesheet" href="/videos/assets/css/login-options.css"> 61 <link href="/videos/assets/css/searchbar.css" rel="stylesheet"> 62 <!-- /css --> 63 64 <!-- reCAPTCHA Enterprise -->
vendor: 70 bytes, lines 64-65
64 65 <script src="https://www.google.com/recaptcha/enterprise.js?render=
656Ld3YiAcAAAAAGVgqURL_hmxqsn8q0liHgBRqkt9
vendor: 15 bytes, lines 65-67
65"></script> 66 67
67<!-- Begin GA SETUP -->
vendor: 66 bytes, lines 67-68
67 68 <script async src="https://www.googletagmanager.com/gtag/js?id=
68UA-31833046-2
vendor: 12 bytes, line 68
68"></script>
69<script id="google-analytics"> 70 window.dataLayer = window.dataLayer || []; 71 function gtag() { 72 dataLayer.push(arguments); 73 }; 74 gtag('js', new Date()); 75 76 const assemblyUserId = getAssemblyUID(); 77 78 gtag('config', 'UA-31833046-2', { 79 'send_page_view': false, 80 }); 81 if (!assemblyUserId) { 82 gtag('config', 'UA-31833046-2'); 83 } else { 84 gtag('config', 'UA-31833046-2', { 85 'user_id': assemblyUserId 86 }); 87 } 88</script>
88 89 90 <!-- Init Mixpanel & track page view --> 91 92
93<script type="text/javascript"> 94 // Mixpanel SDK 95 (function (f, b) { 96 if (!b.__SV) { 97 var e, g, i, h; 98 window.mixpanel = b; 99 b._i = []; 100 b.init = function (e, f, c) { 101 function g(a, d) { 102 var b = d.split("."); 103 2 == b.length && ((a = a[b[0]]), (d = b[1])); 104 a[d] = function () { 105 a.push([d].concat(Array.prototype.slice.call(arguments, 0))); 106 }; 107 } 108 var a = b; 109 "undefined" !== typeof c ? (a = b[c] = []) : (c = "mixpanel"); 110 a.people = a.people || []; 111 a.toString = function (a) { 112 var d = "mixpanel"; 113 "mixpanel" !== c && (d += "." + c); 114 a || (d += " (stub)"); 115 return d; 116 }; 117 a.people.toString = function () { 118 return a.toString(1) + ".people (stub)"; 119 }; 120 i = "disable time_event track track_pageview track_links track_forms track_with_groups add_group set_group remove_group register register_once alias unregister identify name_tag set_config reset opt_in_tracking opt_out_tracking has_opted_in_tracking has_opted_out_tracking clear_opt_in_out_tracking start_batch_senders people.set people.set_once people.unset people.increment people.append people.union people.track_charge people.clear_charges people.delete_user people.remove".split( " "); 121 for (h = 0; h < i.length; h++) g(a, i[h]); 122 var j = "set set_once union unset remove delete".split(" "); 123 a.get_group = function () { 124 function b(c) { 125 d[c] = function () { 126 call2_args = arguments; 127 call2 = [c].concat(Array.prototype.slice.call(call2_args, 0)); 128 a.push([e, call2]); 129 }; 130 } 131 for ( var d = {}, e = ["get_group"].concat( Array.prototype.slice.call(arguments, 0)), c = 0; c < j.length; c++) b(j[c]); 132 return d; 133 }; 134 b._i.push([e, f, c]); 135 }; 136 b.__SV = 1.2; 137 e = f.createElement("script"); 138 e.type = "text/javascript"; 139 e.async = !0; 140 e.src = "undefined" !== typeof MIXPANEL_CUSTOM_LIB_URL ? MIXPANEL_CUSTOM_LIB_URL : "file:" === f.location.protocol && "//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//) ? "https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js" : "//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js"; 141 g = f.getElementsByTagName("script")[0]; 142 g.parentNode.insertBefore(e, g); 143 } 144 })(document, window.mixpanel || []); 145 146 // Mixpanel initialization 147 mixpanel.init("794029538aa6613314df04b12f293456", { persistence: "localStorage" }); // debug: true, 148 149 // Register mixpanel super properties 150 mixpanel.register({ 151 assembly_uid: getAssemblyUID(), 152 user_agent: navigator.userAgent, 153 platform: "desktop", 154 // Set mixpanel's device_id to the wshh uid 155 // it will be set as distinct_id in Mixpanel as well since there is not user_id: https://docs.mixpanel.com/docs/tracking-methods/id-management/identifying-users-simplified 156 $device_id: getWSHHUID(), 157 }); 158 159 // Track page view 160 mixpanel.track_pageview({ 161 page: "singup_options", 162 counts_as_page_load: true, 163 }); 164 165 const getPageFromPathname = (pathname) => { 166 if (!pathname) return ''; 167 const pegaPath = pathname.split('/') || []; 168 let page = pegaPath.length > 1 ? pegaPath[1] : pathname; 169 170 if (page === 'videos') page = 'home'; 171 else if (page === '') page = 'clean_home'; 172 173 return page; 174 }; 175 176 const trackMixpanelLinkEvent = function(elementId, eventName, extraProps = {}) { 177 extraProps.page = getPageFromPathname(document.location.pathname); 178 mixpanel.track_links(elementId, eventName, extraProps); 179 } 180 181 const trackMixpanelEvent = function(eventName, extraProps = {}) { 182 extraProps.page = getPageFromPathname(document.location.pathname); 183 try { 184 mixpanel.track(eventName, extraProps); 185 } catch (error) { 186 console.error("mixpanel-sdk Error logging mixpanel event:", error); 187 } 188 } 189 190 trackMixpanelLinkEvent('#deals', 'deals_btn_click'); 191 // Source code 192 // https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js 193</script>
193 194</head> 195 196<body> 197 <!-- Bootstrap script --> 198
198<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
198 199
199<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
199 200 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css"> 201 <!-- The core Firebase JS SDK is always required and must be listed first -->
202<script type="text/javascript" src="https://www.gstatic.com/firebasejs/8.10.1/firebase-app.js"></script>
202 203 204<!-- TODO: Add SDKs for Firebase products that you want to use https://firebase.google.com/docs/web/setup#available-libraries -->
205<script type="text/javascript" src="https://www.gstatic.com/firebasejs/8.10.1/firebase-auth.js"></script>
vendor: 1 bytes, line 205
205
206<script type="text/javascript" src="https://www.gstatic.com/firebasejs/8.10.1/firebase-analytics.js"></script>
vendor: 1 bytes, line 206
206
207<script type="text/javascript" src="https://www.gstatic.com/firebasejs/8.10.1/firebase-storage.js"></script>
vendor: 1 bytes, line 207
207
208<script type="text/javascript" src="https://www.gstatic.com/firebasejs/8.10.1/firebase-messaging.js"></script>
208 209
210<script type="text/javascript"> 211 // Your web app's Firebase configuration 212 // For Firebase JS SDK v7.20.0 and later, measurementId is optional 213 const firebaseConfig = { 214 apiKey: "AIzaSyCHcbax-cz17PSX-2PsHgLcR4SI6RK9B1A", 215 authDomain: "auth.worldstar.com", 216 databaseURL: "https://wshh-b00d4.firebaseio.com", 217 projectId: "wshh-b00d4", 218 storageBucket: "wshh-b00d4.appspot.com", 219 messagingSenderId: "291183115057", 220 appId: "1:291183115057:web:9e4524f783be0c3d3f0e10", 221 measurementId: "G-HM4QS6BBEL" 222 }; 223 224 const TEN_YEARS = 24 * 365 * 10; 225 226 // Initialize Firebase 227 firebase.initializeApp(firebaseConfig); 228 // Get the Analytics service for the app 229 const analyticsService = firebase.analytics(); 230 // Get the Auth service for the app 231 const auth = firebase.auth(); 232 // Set the app's storage location 233 const storageRef = firebase.app().storage('gs://wshh-user-uploads/').ref(); 234 235 const fbPathname = window.location.pathname.split('/').pop(); 236 237 // Helper functions 238 const getProfileImageURL = function(user) { 239 // Check if this is the photoURL generated by us using the timestamp 240 if (user.photoURL) { 241 return user.photoURL; 242 } 243 return ''; 244 } 245 246 const getUserID = function() { 247 if (auth.currentUser) { 248 return auth.currentUser.uid; 249 } 250 return null; 251 } 252 // Helper functions end 253 254 const updateUserState = function(user, callback) { 255 if (!user) return; 256 257 // never delete this cookie 258 if (user.email) setCookie(LIVERAMP_EMAIL_COOKIE, user.email, TEN_YEARS); 259 260 const username = user.displayName || ''; 261 const userImg = getProfileImageURL(user); 262 $('.username').text(username).show(600); 263 264 if (userImg) { 265 $('.profile-icon-txt').hide(500); 266 $('.profile-icon-img').attr('src', userImg).show(600); 267 } else { 268 $('.profile-icon-img').hide(0); 269 $('.profile-icon-txt').text(username[0]).show(0); 270 } 271 272 typeof callback === 'function' && callback(); 273 } 274 275 const selectVideoEv = function(video_id, page, section, platform = '', cohort = '') { 276 logFirebaseEvent( 277 'select_video', 278 { 279 'extra': page, 280 'section': section, 281 'vid': video_id, 282 'platform': platform, 283 } 284 ); 285 trackMixpanelEvent( 286 'select_video', 287 { 288 'section': section, 289 'video_id': video_id, 290 ...(cohort !== '' && { 'cohort': cohort }), 291 } 292 ); 293 } 294 295 /** 296 * Logs a Firebase event. 297 * 298 * NOTE: event name character limit is 40 characters. (see https://firebase.google.com/docs/reference/cpp/group/event-names#:~:text=Event%20names%20can%20be%20up,start%20with%20an%20alphabetic%20character.) 299 * @param {string} event - The name of the event 300 * @param {object} data - The parameters to pass to the event 301 */ 302 const logFirebaseEvent = function(event, data = {}) { 303 data.page = document.location.pathname.substring(1); 304 try { 305 firebase.analytics().logEvent(event, data); 306 } catch (error) { 307 console.error("firebase-sdk Error logging firebase event:", error); 308 } 309 } 310 311 const logoutUser = function() { 312 auth.signOut() 313 .then(function() { 314 logFirebaseEvent('logout_tapped'); 315 trackMixpanelEvent('logout_tapped'); 316 window.location = '/'; 317 }).catch(function(err) { 318 setError(err); 319 console.error("firebase-sdk Error in logoutUser:", err); 320 }); 321 } 322 323 const sendPasswordResetEmail = function(email, cb) { 324 const url = 'https://worldstar.com/login-options'; 325 const actionCodeSettings = { 326 'url': url, 327 'android': { 328 'installApp': true, 329 'packageName': 'com.pt.wshhp', 330 }, 331 'iOS': { 332 'bundleId': 'com.wshh.com', 333 }, 334 'handleCodeInApp': true, 335 } 336 auth 337 .sendPasswordResetEmail(email, actionCodeSettings) 338 .then(function() { 339 logFirebaseEvent('reset_password_tapped'); 340 trackMixpanelEvent('reset_password_tapped'); 341 cb ? cb() : null; 342 }) 343 .catch(function(err) { 344 setError(err); 345 console.error("firebase-sdk Error sendPasswordResetEmail:", err); 346 }); 347 } 348 349 const resetPassword = function(code, newPassword) { 350 try { 351 auth.confirmPasswordReset(code, newPassword) 352 .then(function() { 353 window.location = '/reset-success'; 354 }).catch(function(err) { 355 setError(err); 356 console.error("firebase-sdk Error in confirmPasswordReset:", err); 357 }); 358 } catch (err) { 359 console.error("firebase-sdk Error exception caught in confirmPasswordReset:", err); 360 } 361 } 362 363 const signUpUser = function(details = {}) { 364 const email = details.email; 365 const password = details.password; 366 367 // displayName 368 const extra = details.extra; 369 370 try { 371 auth 372 .createUserWithEmailAndPassword(email, password) 373 .then(function(cred) { 374 const user = cred.user; 375 // TODO bring back anonymous linking 376 // we have been doing anonymous linking wrong which is causing it to be wonky 377 // this link can help us do it right when we are ready to implement it, hopefully after single sign on 378 // https://stackoverflow.com/questions/39088876/firebase-convert-anonymous-user-account-to-permanent-account-error 379 // const credential = firebase.auth.EmailAuthProvider.credential(email, password); 380 // linkUserToProvider(credential) 381 382 // Update a temporary display name = email 383 user.updateProfile(extra); 384 // save the user in spanner via mobile-api, it will redirect the user to the profile page 385 saveUserToWS(user); 386 }) 387 .catch(function(err) { 388 const eventData = { 389 'email': email, 390 // error codes available: https://firebase.google.com/docs/reference/js/v8/firebase.auth.Auth#createuserwithemailandpassword 391 'errorCode': err.code, 392 }; 393 logFirebaseEvent('account_creation_failed', eventData); 394 trackMixpanelEvent('account_creation_failed', eventData); 395 setError(err); 396 console.error("firebase-sdk Error in createUserWithEmailAndPassword:", err); 397 }); 398 } catch (err) { 399 const eventData = { 400 'email': email, 401 'errorCode': err.code, 402 }; 403 logFirebaseEvent('account_creation_failed', eventData); 404 trackMixpanelEvent('account_creation_failed', eventData); 405 setError(err); 406 console.error("firebase-sdk Error exception caught in signUpUser:", err); 407 } 408 } 409 410 const sendEmailVerification = function() { 411 const actionCodeSettings = { 412 'url': 'https://worldstar.com/profile', 413 'android': { 414 'installApp': true, 415 'packageName': 'com.pt.wshhp', 416 }, 417 'iOS': { 418 'bundleId': 'com.wshh.com', 419 } 420 }; 421 auth.currentUser 422 .sendEmailVerification(actionCodeSettings) 423 .then(function() { 424 logFirebaseEvent('verify_email_prompt_resend_confirmation'); 425 trackMixpanelEvent('verify_email_prompt_resend_confirmation'); 426 }) 427 .catch(function(err) { 428 logFirebaseEvent('send_email_verification_failed'); 429 trackMixpanelEvent('send_email_verification_failed'); 430 console.error("firebase-sdk Error exception in sendEmailVerification:", err); 431 }); 432 } 433 434 const loginUser = function(details = {}) { 435 const email = details.email; 436 const password = details.password; 437 try { 438 auth 439 .signInWithEmailAndPassword(email, password) 440 .then(function() { 441 // Get provider credential data from sessionStorage 442 const credential = sessionStorage.cred; 443 if (credential) { 444 const credentialFromJSON = firebase.auth.AuthCredential.fromJSON(credential); 445 linkUserToProvider(credentialFromJSON);
446 sessionStorage.removeItem('cred'); 447 }; 448 logFirebaseEvent('login_succeeded'); 449 trackMixpanelEvent('login_succeeded'); 450 window.location = '/profile'; 451 }) 452 .catch(function(err) { 453 const eventData = { 454 'email': email, 455 }; 456 logFirebaseEvent('login_failed', eventData); 457 trackMixpanelEvent('login_failed', eventData); 458 setError(err); 459 console.error("firebase-sdk Error exception in signInWithEmailAndPassword:", err); 460 }); 461 } catch (err) { 462 const eventData = { 463 'email': email, 464 }; 465 logFirebaseEvent('login_failed', eventData); 466 trackMixpanelEvent('login_failed', eventData); 467 setError(err); 468 console.error("firebase-sdk Error exception in loginUser:", err); 469 } 470 } 471 472 const linkUserToProvider = function(credential, user = auth.currentUser) { 473 user.linkWithCredential(credential) 474 .catch(function(err) { 475 console.error("firebase-sdk Error in linkUserToProvider user.linkWithCredential:", err.message); 476 }); 477 } 478 479 $(window).on('load', function() { 480 /* 481 Adding these events from here since I am certain I'll have access to the firebase sdk. 482 */ 483 // Profile Icon 484 $('#login-icon').click(function() { 485 logFirebaseEvent('profile_icon_tapped'); 486 trackMixpanelEvent('profile_icon_tapped'); 487 }); 488 489 // Home Button 490 $('.navbar-brand').click(function() { 491 logFirebaseEvent('home_button_tapped'); 492 trackMixpanelEvent('home_button_tapped'); 493 }); 494 495 const media = ['facebook', 'twitter', 'reddit', 'all', 'whatsapp']; 496 media.forEach(function(currMedia) { 497 let selector = 'li[data-service="' + currMedia + '"] .shareaholic-share-button-sizing'; 498 $(selector).click(function() { 499 const eventData = { 500 'extra': currMedia 501 }; 502 logFirebaseEvent('share_video', eventData); 503 trackMixpanelEvent('share_video', eventData); 504 }); 505 }); 506 507 // PROFILE PAGE: get the logged user or redirect to signup-options 508 // Other pages related to login or signup processes: redirect to profile if user is logged in 509 auth.onAuthStateChanged((user) => { 510 if (fbPathname === 'profile' || fbPathname === 'edit-profile') { 511 if (user) { 512 // log out anonymous users 513 if (user.isAnonymous) { 514 logoutUser(); 515 } 516 517 // get the current user from spanner, if it does not exists getWSUser will redirect to signup-options 518 getWSUser(function (wsUser) { 519 user 520 .updateProfile({ 521 displayName: wsUser.username, 522 photoURL: wsUser.profile_picture, 523 }) 524 .then(() => updateUserState(user)) 525 }); 526 527 if (!user.emailVerified) { 528 const verificationModal = new bootstrap.Modal(document.getElementById('email-verification-modal')); 529 verificationModal.show(); 530 logFirebaseEvent('verify_email_address_prompt_displayed'); 531 trackMixpanelEvent('verify_email_address_prompt_displayed'); 532 } 533 } else { 534 window.location.href = '/signup-options'; 535 } 536 } 537 else if ((fbPathname === 'login' || fbPathname === 'login-options' || fbPathname === 'signup' || fbPathname === 'signup-options') && user) { 538 window.location.href = '/profile'; 539 } 540 541 // Set the correct url for login icon in navbar 542 if ($('#login-icon')) { 543 if (user) $('#login-icon').attr('href', '/profile'); 544 else $('#login-icon').attr('href', '/signup-options'); 545 } 546 }); 547 }); 548</script>
548 549
550<script type="text/javascript"> 551 if (firebase.messaging.isSupported()) { 552 const messaging = firebase.messaging(); 553 554 // Get registration token. Initially this makes a network call, once retrieved 555 // subsequent calls to getToken will return from cache. 556 messaging.getToken({ 557 vapidKey: 'BGGzqoXPgxKc_926Hixp4fu2uxa_wehF57lhWvu_KeiDKoj0-9i2Fjg5yUlEeB-f0ihbV6Vqumij36cyYd5EpkM' 558 }) 559 .then((currentToken) => { 560 if (currentToken) { 561 // Send the token to your server and update the UI if necessary 562 // console.log('got token', currentToken) 563 } else { 564 // Show permission request UI 565 // console.log('No registration token available. Request permission to generate one.'); 566 } 567 }).catch(function (err) { 568 console.error("Error in firebase-messaging messaging.getToken:", err); 569 }); 570 571 // When a push message is received and the user is currently on a page for your origin, 572 // the message is passed to the page and an onMessage() event is dispatched with the payload of the push message. 573 messaging.onMessage((payload) => { 574 const payloadNotification = payload?.notification; 575 const notificationTitle = payloadNotification?.title; 576 const notificationIcon = payload?.notification?.icon || '/videos/assets/images/circle-crown.png'; 577 const notificationBody = payloadNotification?.body; 578 const notificationClickAction = payloadNotification?.click_action || notificationBody; 579 const notificationOptions = { 580 body: notificationBody, 581 icon: notificationIcon, 582 }; 583 584 const notification = new Notification(notificationTitle, notificationOptions); 585 586 notification.onclick = function (ev) { 587 ev.preventDefault(); 588 window.open(notificationClickAction, '_blank'); 589 notification.close(); 590 } 591 }); 592 } 593</script>
593 594 595<!-- Include Spanner functions -->
596<script src="/utils/spanner.js"></script>
596 597<!-- Include Provider sign in functions -->
598<script src="/utils/provider-sso.js"></script>
598 599<!-- Google Tag Manager (noscript) -->
vendor: 68 bytes, lines 599-600
599 600<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
600GTM-N8PRK68K
vendor: 101 bytes, lines 600-601
600" 601 height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
602<!-- End Google Tag Manager (noscript) --> <div id="wrapper" class="static-login"> 603 <header id="header"> 604 605<div class="navbar-nav"> 606 <nav class="navbar navbar-dark justify-content-between" style="background-color: #121212;"> 607 <div class="justify-content-between" style="display: flex; align-items: center"> 608 <div class="d-flex align-items-center"> 609 <a onclick="onNavLinkClick(event, 'videos/', false)" class="navbar-brand" href="https://worldstarhiphop.com/videos/"><img src="https://worldstarhiphop.com/videos/images/logo_ws_horizontal.png" width="145px" height="30px"></a> 610 <!-- <div class="navbar-text"><a target="_blank" class="nav-link" href="https://worldstardistro.com">DISTRO</a></div> --> 611 <div class="navbar-text"><a class="nav-link" href="https://contact.worldstar.com">CONTACT</a></div> 612 <!-- TODO: restore/update once Flagr Advertise A/B test is complete --> 613 <!-- <div class="navbar-text"><a class="nav-link" href="https://worldstarhiphop.com/videos/vsubmit.php">SUBMIT VIDEO</a></div> --> 614 <div class="navbar-text"><a target="_blank" class="nav-link" href="https://advertise.worldstarhiphop.com">ADVERTISE</a></div> 615 <div class="navbar-text"><a id="deals" class="nav-link" href="https://deals.worldstarhiphop.com/">DEALS</a></div> 616 617<div id="containerSearchBar" class="relative pt-2"> 618 <div class="search-input-container" 619 > 620 <input 621 type="text" 622 id="searchInput" 623 class="search-input search-input-desktop" 624 placeholder="Search..." 625 /> 626 <button id="searchButton" class="search-button"> 627 <span class="search-button-icon-container bi bi-search h6"></span> 628 </button> 629 </div> 630 <div 631 class="suggestion-container" 632 style="width:20vw;" 633 ></div> 634 <div 635 class="search-overlay" 636 onclick="closeSuggestionList()" 637 ></div> 638</div> 639
640<script type="text/javascript"> 641 const VIDEO_SEARCH_SUGGESTION_URL = 'https://api-staging.worldstar.com/search/suggestion'; 642 const SEARCH_BAR_CLICK_EVENT = 'search_bar_click'; 643 const SEARCH_BUTTON_CLICK_EVENT = 'search_btn_click'; // used when user clicks on search button or run the search by pressing enter on keyboardpass 644 const SEARCH_SUGGESTION_CLICK_EVENT = 'search_suggestion_clicked'; 645 const SEARCH_SUGGESTION_SECTION = 'search_suggestion'; 646 const SELECT_VIDEO_EVENT = 'select_video'; 647 const TAG_BTN_CLICK_EVENT = 'tag_btn_click'; 648 const SUGGESTION_VIDEOS = 'videos'; 649 const SUGGESTION_TAGS = 'tags'; 650 const pageSize = 40; 651 const isMobileView = false; 652 653 let showSuggestionList = false; 654 let searchTerm = ''; 655 let isLoading = false; 656 let searchResults = { 657 tags: [], 658 videos: [] 659 }; 660 661 const container = document.querySelector('#containerSearchBar'); 662 const searchInput = container.querySelector('#searchInput'); 663 const searchButton = container.querySelector('#searchButton'); 664 const suggestionContainer = container.querySelector('.suggestion-container'); 665 const searchOverlay = container.querySelector('.search-overlay'); 666 667 const renderTags = () => { 668 return ( 669 `<h3 class="result-section-title">TAGS</h3> 670 <ul class="tag-list"> 671 ${searchResults?.tags?.slice(0, 5)?.map(tag => ` 672 <li class="tag-item" data-tag-id="${tag.tagId}"> 673 ${tag.tagName} 674 </li> 675 `).join('')} 676 677 <li 678 class="show-more" 679 style="display:${searchResults?.tags?.length > 5 ? 'block' : 'none'};" 680 id="showMoreTags" 681 >Show more tags</li> 682 </ul> 683 ` 684 ); 685 } 686 687 const renderFullTags = () => { 688 return ( 689 `<div class="result-section-title-container"> 690 <button class="back-button" id="backButtonTags"> 691 BACK 692 </button> 693 <h3 class="result-section-title">ALL TAGS RESULTS</h3> 694 </div> 695 <ul class="tag-list"> 696 ${searchResults?.tags?.map(tag => ` 697 <li class="tag-item" data-tag-id="${tag.tagId}"> 698 ${tag.tagName} 699 </li> 700 `).join('')} 701 </ul> 702 ` 703 ); 704 } 705 706 const renderVideos = () => { 707 return ( 708 `<h3 class="result-section-title">VIDEOS</h3> 709 <ul class="video-list"> 710 ${searchResults?.videos?.slice(0, 5)?.map(video => ` 711 <li class="video-item" data-video-id="${video.encryptedVCode}"> 712 <div class="video-thumbnail"> 713 <img class="video-poster-img" src=${video.imageUrl} alt=${video.title}> 714 </div> 715 <div class="video-info"> 716 <span class="video-title">${video.title}</span> 717 </div> 718 </li> 719 `).join('')} 720 721 <li 722 class="show-more" 723 style="display:${searchResults?.videos?.length > 5 ? 'block' : 'none'};" 724 id="showMoreVideos" 725 >Show more videos</li> 726 </ul> 727 ` 728 ); 729 }; 730 731 const renderFullVideos = () => { 732 return ( 733 `<div class="result-section-title-container"> 734 <button class="back-button" id="backButtonVideos"> 735 BACK 736 </button> 737 <h3 class="result-section-title">ALL VIDEOS RESULTS</h3> 738 </div> 739 <ul class="video-list"> 740 ${searchResults?.videos?.map(video => ` 741 <li class="video-item" data-video-id="${video.encryptedVCode}"> 742 <div class="video-thumbnail"> 743 <img class="video-poster-img" src=${video.imageUrl} alt=${video.title}> 744 </div> 745 <div class="video-info"> 746 <span class="video-title">${video.title}</span> 747 </div> 748 </li> 749 `).join('')} 750 </ul> 751 ` 752 ); 753 }; 754 755 const toggleSuggestionList = (showMoreResults, previousShowMoreResults = '') => { 756 const initialResult = document.getElementById('initialResult'); 757 const moreVideosResult = document.getElementById('moreVideosResult'); 758 const moreTagsResult = document.getElementById('moreTagsResult'); 759 760 switch (showMoreResults) { 761 case SUGGESTION_VIDEOS: 762 initialResult?.classList.remove('slide-in-from-left'); 763 initialResult?.classList.add('slide-out-left'); 764 moreVideosResult?.classList.remove('slide-out-right'); 765 moreVideosResult?.classList.add('slide-in-from-right'); 766 break; 767 case SUGGESTION_TAGS: 768 initialResult?.classList.remove('slide-in-from-left'); 769 initialResult?.classList.add('slide-out-left'); 770 moreTagsResult?.classList.remove('slide-out-right'); 771 moreTagsResult?.classList.add('slide-in-from-right'); 772 break; 773 default: 774 initialResult?.classList.remove('slide-out-left'); 775 initialResult?.classList.add('slide-in-from-left'); 776 if (previousShowMoreResults === SUGGESTION_TAGS) { 777 moreTagsResult?.classList.remove('slide-in-from-right'); 778 moreTagsResult?.classList.add('slide-out-right'); 779 } else if (previousShowMoreResults === SUGGESTION_VIDEOS) { 780 moreVideosResult?.classList.remove('slide-in-from-right'); 781 moreVideosResult?.classList.add('slide-out-right'); 782 } 783 break; 784 }; 785 }; 786 787 const handleVideoClick = (videoId) => { 788 const video = searchResults.videos.find(v => v.encryptedVCode === videoId); 789 if (!video) return; 790 791 const { title, encryptedVCode, videoUrl } = video; 792 const data = { 793 title, 794 video_id: encryptedVCode, 795 section: SEARCH_SUGGESTION_SECTION, 796 }; 797 trackMixpanelEvent(SELECT_VIDEO_EVENT, data); 798 trackMixpanelEvent(SEARCH_SUGGESTION_CLICK_EVENT, { 799 ...data, 800 type: SUGGESTION_VIDEOS, 801 }); 802 803 closeSuggestionList(); 804 805 // redirect to the video's URL 806 const isCurrentDomainClean = isCleanDomain(window.location.hostname); 807 const isCleanVideo = isCleanDomain(videoUrl); 808 // add extra parameters if cross domain 809 const onClickVideoUrl = isCurrentDomainClean === isCleanVideo ? videoUrl : getFullURL(videoUrl); 810 window.location.href = onClickVideoUrl; 811 }; 812
813 const handleTagClick = (tagId) => { 814 const tag = searchResults.tags.find(v => v.tagId === (tagId ? parseInt(tagId) : -1)); 815 if (!tag) return; 816 817 const { tagName, slug } = tag; 818 const data = { 819 tag: tagName, 820 tag_id: tagId?.toString(), 821 section: SEARCH_SUGGESTION_SECTION, 822 }; 823 trackMixpanelEvent(TAG_BTN_CLICK_EVENT, data); 824 trackMixpanelEvent(SEARCH_SUGGESTION_CLICK_EVENT, { 825 ...data, 826 type: SUGGESTION_TAGS, 827 }); 828 829 closeSuggestionList(); 830 831 // redirect to klp page (add extra parameters in cross domain) 832 const host = window.location.protocol + "//" + window.location.host; 833 const tagURL = host + '/watch/' + slug; 834 window.location.href = getUncleanClickURL(tagURL); 835 }; 836 837 const attachSuggestionEventListeners = () => { 838 container.querySelectorAll('.tag-item').forEach(tag => { 839 tag.addEventListener('click', () => handleTagClick(tag.dataset.tagId)); 840 }); 841 842 container.querySelectorAll('.video-item').forEach(video => { 843 video.addEventListener('click', () => handleVideoClick(video.dataset.videoId)); 844 }); 845 846 const showMoreVideosButton = document.getElementById('showMoreVideos'); 847 const showMoreTagsButton = document.getElementById('showMoreTags'); 848 showMoreVideosButton?.addEventListener('click', () => toggleSuggestionList(SUGGESTION_VIDEOS)); 849 showMoreTagsButton?.addEventListener('click', () => toggleSuggestionList(SUGGESTION_TAGS)); 850 851 const backButtonTags = document.getElementById('backButtonTags'); 852 backButtonTags?.addEventListener('click', () => toggleSuggestionList('', SUGGESTION_TAGS)); 853 const backButtonVideos = document.getElementById('backButtonVideos'); 854 backButtonVideos?.addEventListener('click', () => toggleSuggestionList('', SUGGESTION_VIDEOS)); 855 }; 856 857 const renderSuggestions = () => { 858 if (!showSuggestionList || searchTerm.length < 3) { 859 suggestionContainer.innerHTML = ''; 860 suggestionContainer.style.display = 'none'; 861 searchOverlay.style.display = 'none'; 862 return; 863 } 864 865 suggestionContainer.style.display = 'block'; 866 searchOverlay.style.display = 'block'; 867 let content = ''; 868 869 // Calculate the suggestion list height 870 calculateHeight(); 871 872 if (isLoading) { 873 content = ` 874 <div class="search-loading-container"> 875 <div class="loading-spinner"></div> 876 </div> 877 `; 878 } else if (searchResults?.videos?.length > 0 || searchResults?.tags?.length > 0) { 879 content = ` 880 <div 881 class="suggestion-result-container custom-scrollbar" 882 > 883 <h3 class="suggestion-result-container-header"> 884 SEARCH <span class="suggestion-result-container-header-highlight">RESULTS</span> 885 </h3> 886 <div class="results-container" id="initialResult"> 887 ${renderTags()} 888 ${renderVideos()} 889 </div> 890 <div class="results-container more-results hidden-section" id="moreTagsResult"> 891 ${renderFullTags()} 892 </div> 893 <div class="results-container more-results hidden-section" id="moreVideosResult"> 894 ${renderFullVideos()} 895 </div> 896 </div> 897 `; 898 } else { 899 content = ` 900 <span class="no-results"> 901 No results 902 </span> 903 `; 904 } 905 906 suggestionContainer.innerHTML = content; 907 attachSuggestionEventListeners(); 908 } 909 910 const closeSuggestionList = () => { 911 showSuggestionList = false; 912 searchTerm = ''; 913 toggleSuggestionList(''); 914 searchInput.value = ''; 915 renderSuggestions(); 916 }; 917 918 const handleSearchInputChange = async (e) => { 919 searchTerm = e.target.value; 920 if (searchTerm.length >= 3) { 921 isLoading = true; 922 renderSuggestions(); 923 try { 924 const response = await fetch( 925 `${VIDEO_SEARCH_SUGGESTION_URL}?searchTerm=${searchTerm}&pageSize=${pageSize}` 926 ); 927 const data = await response.json(); 928 929 if (data) { 930 searchResults = { 931 videos: data.videos?.result || [], 932 tags: data.tags || [] 933 }; 934 } 935 } catch (error) { 936 console.error('Error fetching search results:', error); 937 } finally { 938 isLoading = false;
939 renderSuggestions(); 940 } 941 } else { 942 searchResults = { tags: [], videos: [] }; 943 renderSuggestions(); 944 } 945 } 946 947 const handleSearchIconClick = (searchValue) => { 948 trackMixpanelEvent(SEARCH_BUTTON_CLICK_EVENT); 949 950 var searchValue = searchInput?.value?.trim() || ''; 951 if (searchValue) { 952 var newUrl = '/search/' + encodeURIComponent(searchValue); 953 window.location.href = getUncleanClickURL(newUrl); 954 } 955 }; 956 957 const attachEventListeners = () => { 958 searchInput.addEventListener('input', (e) => handleSearchInputChange(e)); 959 searchInput.addEventListener('focus', () => { 960 showSuggestionList = true; 961 trackMixpanelEvent(SEARCH_BAR_CLICK_EVENT); 962 }); 963 searchInput.addEventListener('keydown', (e) => { 964 if (e.key === 'Enter') { 965 handleSearchIconClick(); 966 } 967 }); 968 searchButton.addEventListener('click', () => handleSearchIconClick()); 969 } 970 971 const calculateHeight = () => { 972 if (!suggestionContainer) return; 973 974 let suggestionListHeight = -1; 975 976 if (searchResults?.videos?.length > 0 || searchResults?.tags?.length > 0) { 977 const searchBarRect = searchInput.getBoundingClientRect(); 978 const distanceToBottom = window.innerHeight - searchBarRect.bottom; 979 const paddingBottom = 20; 980 suggestionListHeight = distanceToBottom ? 981 Math.round(distanceToBottom - paddingBottom) : -1; 982 } 983 984 const height = suggestionListHeight > 0 985 ? `${suggestionListHeight}px` 986 : 'fit-content'; 987 988 suggestionContainer.style.height = height; 989 } 990 991 const handleMobileScroll = () => { 992 if (!searchInput) return; 993 searchInput.blur(); 994 }; 995 996 attachEventListeners(); 997 998 // Add window resize listener 999 if (isMobileView) { 1000 document.addEventListener('scroll', handleMobileScroll, { 1001 passive: true, 1002 }); 1003 document.addEventListener('touchmove', handleMobileScroll, { 1004 passive: true, 1005 }); 1006 } else { 1007 window.addEventListener('resize', () => calculateHeight()); 1008 } 1009 1010</script>
1010 1011 </div> 1012 1013 <div style="display: flex; align-items: center"> 1014 <!-- Will be used when we unify domains --> 1015 <!-- <div id="login-icon" class="navbar-text" data-toggle="modal" data-target="#loginModal"> 1016 <a onclick="event.preventDefault()"> 1017 LOG IN 1018 </a> 1019 </div> 1020 <div class="profile-icon"> 1021 <a href="profile.php"> 1022 <img class="profile-icon-img" width="32" height="32" src=""> 1023 <div class="profile-icon-txt"></div> 1024 </a> 1025 </div> --> 1026 <div class="navbar-text"> 1027 <a id="submit-videos-btn" onclick="onNavLinkClick(event, 'submit-video', true, 'submit_video_btn_click')" class="round-btn" class="nav-link" href="https://worldstar.com/submit-video">Submit Videos</a> 1028 </div> 1029 <div class="navbar-text"> 1030 <a id="login-icon" onclick="onNavLinkClick(event, 'profile', true)" href="https://worldstar.com/profile"> 1031 <img width="22px" height="22px" src="https://worldstarhiphop.com/videos/images/[email protected]"> 1032 </a> 1033 </div> 1034 </div> 1035 </div> 1036 </nav> 1037</div> 1038
1039<script type="text/javascript"> 1040 document.getElementById('search-form')?.addEventListener('submit', function(event) { 1041 // Prevent form submission 1042 event.preventDefault(); 1043 1044 trackMixpanelEvent('search_btn_click'); 1045 var searchValue = document.getElementById('searchInput')?.value?.trim() || ''; 1046 if (searchValue) { 1047 var newUrl = '/search/' + encodeURIComponent(searchValue); 1048 window.location.href = getUncleanClickURL(newUrl); 1049 } 1050 }); 1051</script>
1051 1052 </header> 1053 1054 <div class="container login-wrapper"> 1055 <div class="page-header text-center"> 1056 <h3>Sign Up for Worldstar</h3> 1057 <p>Create a profile to access Live streams,<br/> start streaming and more.</p> 1058 <p class="end-note">Already have an account? <a id="login-link" href="/login-options" class="red small font-weight-bold">LOG IN</a></p> 1059 </div> 1060 <div class="text-center" id="login-section"> 1061 <div id="invalid-form-feedback" class="invalid-feedback"></div> 1062 <a id="signup-link" href="/signup"> 1063 <button class="btn custom-btn"> 1064 <span><img width="18px" height="18px" src="https://worldstarhiphop.com/videos/assets/images/icon_email.svg"></span> 1065 <span>SIGN UP WITH EMAIL</span> 1066 </button> 1067 </a> 1068 <div class="hr-sect">OR</div> 1069 <button class="btn custom-btn" onclick="providerSignIn('google')"> 1070 <span><img width="18px" height="18px" src="https://worldstarhiphop.com/videos/assets/images/icon_google.svg"></span> 1071 <span>CONTINUE WITH GOOGLE</span> 1072 </button> 1073 <button class="btn custom-btn" onclick="providerSignIn('facebook')"> 1074 <span><img width="18px" height="18px" src="https://worldstarhiphop.com/videos/assets/images/icon_facebook.svg"></span> 1075 <span>CONTINUE WITH FACEBOOK</span> 1076 </button> 1077 <button class="btn custom-btn" onclick="providerSignIn('apple')"> 1078 <span><img width="18px" height="18px" src="https://worldstarhiphop.com/videos/assets/images/icon_apple.svg"></span> 1079 <span>CONTINUE WITH APPLE</span> 1080 </button> 1081 <p class="faint small terms-note">By creating an account, I agree to the <a href="https://worldstar.com/terms-of-service">Terms</a> and <a href="https://worldstar.com/privacy-policy">Privacy Policy</a>.</p> 1082 </div> 1083</div> 1084
1085<script type="text/javascript"> 1086 const redirectURL = getRedirectURL(); 1087 const errMessage = getURLParam('error'); 1088 1089 if (errMessage) { 1090 setError({ message: errMessage }); 1091 } 1092 1093 if (redirectURL) { 1094 $('#signup-link').attr('href', 'signup?redirect_url=' + redirectURL); 1095 $('#login-link').attr('href', 'login-options?redirect_url=' + redirectURL); 1096 } 1097</script>
1097 1098 1099 1100 <center> 1101 <footer id="footer"> 1102 <div class="f1"> 1103 <div class="f2"> 1104 <div class="f3"> 1105 <strong class="footer-logo"><a onclick="onFooterLinkClick(event, 'videos', false)" href="https://worldstarhiphop.com/videos/">World Star Hip Hop</a></strong> 1106 <ul class="footer-nav"> 1107 <li><a href="https://contact.worldstar.com/hc/en-us/articles/25632693260955-Digital-Services-Act-DSA-Contact-Information-for-WorldStarHipHop-Users-and-Authorities">EU DSA</a></li> 1108 <li><a onclick="onFooterLinkClick(event, 'privacy-policy', true)" href="https://worldstar.com/privacy-policy">PRIVACY</a></li> 1109 <li><a onclick="onFooterLinkClick(event, 'terms-of-service', true)" href="https://worldstar.com/terms-of-service">TERMS</a></li> 1110 <li><a onclick="onFooterLinkClick(event, 'dmca', true)" href="https://worldstar.com/dmca">DMCA</a></li> 1111 <li><a onclick="onFooterLinkClick(event, 'submit-video', true)" href="https://worldstar.com/submit-video">SUBMIT VIDEO</a></li> 1112 </ul> 1113 </div> 1114 </div> 1115 </div> 1116 </footer> 1117
1117<script type="text/javascript"> 1118 function onFooterLinkClick(e, page, isClean) { 1119 e.preventDefault(); 1120 // redirect (add extra parameters in cross domain) 1121 const host = window.location.protocol + "//" + window.location.host; 1122 const tagURL = host + "/" + page; 1123 window.location.href = isClean ? getCleanClickURL(tagURL) : getUncleanClickURL(tagURL); 1124 }; 1125 </script>
1125 </div> 1126 1127
1127<script type="text/javascript"> 1128 $(document).ready(function() { 1129 logFirebaseEvent('display_signup_options_ui'); 1130 trackMixpanelEvent('display_signup_options_ui'); 1131 }); 1132 </script>
1132 1133 1134
1134<script 1135 type="text/javascript" 1136 src="https://s.skimresources.com/js/265960X1751083.skimlinks.js" 1137 ></script>
1137 1138</body> 1139 1140</html>
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.