diff --git a/chrome_tixcraft.py b/chrome_tixcraft.py index 4c1509d..94918f4 100644 --- a/chrome_tixcraft.py +++ b/chrome_tixcraft.py @@ -44,7 +44,7 @@ except Exception as exc: print(exc) pass -CONST_APP_VERSION = "MaxBot (2024.03.31)" +CONST_APP_VERSION = "MaxBot (2024.04.01)" CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" CONST_MAXBOT_CONFIG_FILE = "settings.json" @@ -725,27 +725,31 @@ def get_driver_by_config(config_dict): print("create web driver object fail @_@;") else: try: - NETWORK_BLOCKED_URLS = ['*/adblock.js' - ,'*/google_ad_block.js' - ,'*google-analytics.*' - ,'*googletagmanager.*' - ,'*googletagservices.*' - ,'*googlesyndication.*' - ,'*play.google.com/*' - ,'*cdn.cookielaw.org/*' - ,'*fundingchoicesmessages.google.com/*' - ,'*.doubleclick.net/*' - ,'*.rollbar.com/*' - ,'*.cloudfront.com/*' - ,'*.lndata.com/*' - ,'*.twitter.com/i/*' - ,'*platform.twitter.com/*' - ,'*syndication.twitter.com/*' - ,'*youtube.com/*' - ,'*player.youku.*' - ,'*.clarity.ms/*' - ,'*img.uniicreative.com/*' - ,'*e2elog.fetnet.net*'] + NETWORK_BLOCKED_URLS = [ + '*.clarity.ms/*', + '*.cloudfront.com/*', + '*.doubleclick.net/*', + '*.lndata.com/*', + '*.rollbar.com/*', + '*.twitter.com/i/*', + '*/adblock.js', + '*/google_ad_block.js', + '*cityline.com/js/others.min.js', + '*anymind360.com/*', + '*cdn.cookielaw.org/*', + '*e2elog.fetnet.net*', + '*fundingchoicesmessages.google.com/*', + '*google-analytics.*', + '*googlesyndication.*', + '*googletagmanager.*', + '*googletagservices.*', + '*img.uniicreative.com/*', + '*platform.twitter.com/*', + '*play.google.com/*', + '*player.youku.*', + '*syndication.twitter.com/*', + '*youtube.com/*', + ] if config_dict["advanced"]["hide_some_image"]: NETWORK_BLOCKED_URLS.append('*.woff') @@ -4700,18 +4704,20 @@ def cityline_purchase_button_press(driver, config_dict): if config_dict["advanced"]["verbose"]: show_debug_message = True - date_auto_select_mode = config_dict["date_auto_select"]["mode"] date_keyword = config_dict["date_auto_select"]["date_keyword"].strip() auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"] if show_debug_message: print("date_keyword:", date_keyword) + is_date_assign_by_bot = cityline_date_auto_select(driver, date_auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable) is_button_clicked = False if is_date_assign_by_bot: + print("press purchase button") is_button_clicked = press_button(driver, By.CSS_SELECTOR, 'button.purchase-btn') + time.sleep(0.2) return is_button_clicked @@ -10906,6 +10912,7 @@ def main(args): if not is_quit_bot: url, is_quit_bot = get_current_url(driver) + #print("url:", url) if is_quit_bot: try: diff --git a/config_launcher.py b/config_launcher.py index 984f184..49dc143 100644 --- a/config_launcher.py +++ b/config_launcher.py @@ -24,7 +24,7 @@ import webbrowser import util -CONST_APP_VERSION = "MaxBot (2024.03.31)" +CONST_APP_VERSION = "MaxBot (2024.04.01)" CONST_MAXBOT_LAUNCHER_FILE = "config_launcher.json" CONST_MAXBOT_CONFIG_FILE = "settings.json" diff --git a/kktix_status.py b/kktix_status.py index e549d4b..32dc3c0 100644 --- a/kktix_status.py +++ b/kktix_status.py @@ -29,7 +29,7 @@ from datetime import datetime import util -CONST_APP_VERSION = "MaxBot (2024.03.31)" +CONST_APP_VERSION = "MaxBot (2024.04.01)" CONST_MAXBOT_CONFIG_FILE = "settings.json" CONST_MAXBOT_KKTIX_CONFIG_FILE = "kktix.json" diff --git a/nodriver_tixcraft.py b/nodriver_tixcraft.py index 58a988d..c5b8e76 100644 --- a/nodriver_tixcraft.py +++ b/nodriver_tixcraft.py @@ -32,7 +32,7 @@ except Exception as exc: print(exc) pass -CONST_APP_VERSION = "MaxBot (2024.03.31)" +CONST_APP_VERSION = "MaxBot (2024.04.01)" CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" CONST_MAXBOT_CONFIG_FILE = "settings.json" @@ -46,6 +46,7 @@ CONST_MAXBLOCK_EXTENSION_FILTER =[ "*.googlesyndication.com/*", "*.ssp.hinet.net/*", "*a.amnet.tw/*", +"*anymind360.com/*", "*adx.c.appier.net/*", "*cdn.cookielaw.org/*", "*cdnjs.cloudflare.com/ajax/libs/clipboard.js/*", @@ -380,7 +381,7 @@ async def nodriver_kktix_travel_price_list(tab, config_dict, kktix_area_auto_sel ticket_price_list = None try: - ticket_price_list = await tab.select_all('div.display-table-row') + ticket_price_list = await tab.query_selector_all('div.display-table-row') except Exception as exc: ticket_price_list = None print("find ticket-price Exception:") @@ -420,13 +421,15 @@ async def nodriver_kktix_travel_price_list(tab, config_dict, kktix_area_auto_sel row_input = None current_ticket_number = "0" try: - js_attr = await row.get_js_attributes() - row_html = js_attr["innerHTML"] - row_text = js_attr["innerText"] + #js_attr = await row.get_js_attributes() + row_html = await row.get_html() + row_text = util.remove_html_tags(row_html) + row_input = await row.query_selector("input") - if not row_input is None: + if row_input: js_attr_input = await row_input.get_js_attributes() - current_ticket_number = js_attr_input["value"] + if js_attr_input: + current_ticket_number = js_attr_input["value"] except Exception as exc: is_dom_ready = False if show_debug_message: @@ -960,9 +963,12 @@ async def nodriver_get_text_by_selector(tab, my_css_selector, attribute='innerHT try: div_element = await tab.query_selector(my_css_selector) if div_element: - js_attr = await div_element.get_js_attributes() - if js_attr: - div_text = js_attr[attribute] + #js_attr = await div_element.get_js_attributes() + div_text = await div_element.get_html() + + # only this case to remove tags + if attribute=="innerText": + div_text = util.remove_html_tags(div_text) except Exception as exc: print("find verify textbox fail") pass @@ -1654,6 +1660,128 @@ async def nodriver_cityline_login(tab, cityline_account): print(exc) pass +async def nodriver_cityline_date_auto_select(tab, auto_select_mode, date_keyword): + show_debug_message = True # debug. + show_debug_message = False # online + + ret = False + + area_list = None + try: + my_css_selector = "button.date-time-position" + area_list = await tab.query_selector_all(my_css_selector) + except Exception as exc: + print(exc) + + matched_blocks = None + if area_list: + formated_area_list = None + area_list_count = len(area_list) + if show_debug_message: + print("date_list_count:", area_list_count) + + if area_list_count > 0: + formated_area_list = area_list + if show_debug_message: + print("formated_area_list count:", len(formated_area_list)) + + if len(date_keyword) == 0: + matched_blocks = formated_area_list + else: + # match keyword. + if show_debug_message: + print("start to match keyword:", date_keyword) + matched_blocks = [] + + for row in formated_area_list: + row_text = "" + row_html = "" + try: + row_html = await row.get_html() + row_text = util.remove_html_tags(row_html) + # PS: get_js_attributes on cityline due to: the JSON object must be str, bytes or bytearray, not NoneType + #js_attr = await row.get_js_attributes() + #row_html = js_attr["innerHTML"] + #row_text = js_attr["innerText"] + except Exception as exc: + if show_debug_message: + print(exc) + # error, exit loop + break + + if len(row_text) > 0: + if show_debug_message: + print("row_text:", row_text) + is_match_area = util.is_row_match_keyword(date_keyword, row_text) + if is_match_area: + matched_blocks.append(row) + if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM: + break + + if show_debug_message: + if not matched_blocks is None: + print("after match keyword, found count:", len(matched_blocks)) + else: + print("not found date-time-position") + pass + else: + print("date date-time-position is None") + pass + + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) + if not target_area is None: + try: + await target_area.scroll_into_view() + await target_area.click() + ret = True + except Exception as exc: + print(exc) + + return ret + +async def nodriver_check_modal_dialog_popup(tab): + ret = False + try: + el_div = tab.query_selector('div.modal-dialog > div.modal-content') + if el_div: + ret = True + except Exception as exc: + print(exc) + pass + return ret + +async def nodriver_cityline_purchase_button_press(tab, config_dict): + date_auto_select_mode = config_dict["date_auto_select"]["mode"] + date_keyword = config_dict["date_auto_select"]["date_keyword"].strip() + is_date_assign_by_bot = await nodriver_cityline_date_auto_select(tab, date_auto_select_mode, date_keyword) + + is_button_clicked = False + if is_date_assign_by_bot: + print("press purchase button") + await nodriver_press_button(tab, 'button.purchase-btn') + is_button_clicked = True + # wait reCAPTCHA popup. + time.sleep(6) + + return is_button_clicked + +async def nodriver_cityline_close_second_tab(tab, url): + new_tab = tab + #print("tab count:", len(tab.browser.tabs)) + if len(tab.browser.tabs) > 1: + # wait page ready. + time.sleep(0.3) + for tmp_tab in tab.browser.tabs: + if tmp_tab != tab: + tmp_url, is_quit_bot = await nodriver_current_url(tmp_tab) + if len(tmp_url) > 0: + if tmp_url[:5] == "https": + await new_tab.activate() + await tab.close() + time.sleep(0.3) + new_tab = tmp_tab + break + return new_tab async def nodriver_cityline_main(tab, url, config_dict): if 'msg.cityline.com' in url or 'event.cityline.com' in url: @@ -1664,11 +1792,33 @@ async def nodriver_cityline_main(tab, url, config_dict): if len(cityline_account) > 4: await nodriver_cityline_login(tab, cityline_account) - # main page: + tab = await nodriver_cityline_close_second_tab(tab, url) + + # date page. + #https://venue.cityline.com/utsvInternet/EVENT_NAME/eventDetail?event=EVENT_CODE + global cityline_purchase_button_pressed + if not 'cityline_purchase_button_pressed' in globals(): + cityline_purchase_button_pressed = False + if '/eventDetail?' in url: + # detect fail. + #is_modal_dialog_popup = await nodriver_check_modal_dialog_popup(tab) + + if not cityline_purchase_button_pressed: + if config_dict["date_auto_select"]["enable"]: + is_button_clicked = await nodriver_cityline_purchase_button_press(tab, config_dict) + if is_button_clicked: + cityline_purchase_button_pressed = True + else: + cityline_purchase_button_pressed = False + + + # area page: # TODO: #https://venue.cityline.com/utsvInternet/EVENT_NAME/performance?event=EVENT_CODE&perfId=PROFORMANCE_ID pass + return tab + async def nodriver_facebook_main(tab, config_dict): facebook_account = config_dict["advanced"]["facebook_account"].strip() @@ -1766,27 +1916,31 @@ def get_extension_config(config_dict): return conf async def nodrver_block_urls(tab, config_dict): - NETWORK_BLOCKED_URLS = ['*/adblock.js' - ,'*/google_ad_block.js' - ,'*google-analytics.*' - ,'*googletagmanager.*' - ,'*googletagservices.*' - ,'*googlesyndication.*' - ,'*play.google.com/*' - ,'*cdn.cookielaw.org/*' - ,'*fundingchoicesmessages.google.com/*' - ,'*.doubleclick.net/*' - ,'*.rollbar.com/*' - ,'*.cloudfront.com/*' - ,'*.lndata.com/*' - ,'*.twitter.com/i/*' - ,'*platform.twitter.com/*' - ,'*syndication.twitter.com/*' - ,'*youtube.com/*' - ,'*player.youku.*' - ,'*.clarity.ms/*' - ,'*img.uniicreative.com/*' - ,'*e2elog.fetnet.net*'] + NETWORK_BLOCKED_URLS = [ + '*.clarity.ms/*', + '*.cloudfront.com/*', + '*.doubleclick.net/*', + '*.lndata.com/*', + '*.rollbar.com/*', + '*.twitter.com/i/*', + '*/adblock.js', + '*/google_ad_block.js', + '*cityline.com/js/others.min.js', + '*anymind360.com/*', + '*cdn.cookielaw.org/*', + '*e2elog.fetnet.net*', + '*fundingchoicesmessages.google.com/*', + '*google-analytics.*', + '*googlesyndication.*', + '*googletagmanager.*', + '*googletagservices.*', + '*img.uniicreative.com/*', + '*platform.twitter.com/*', + '*play.google.com/*', + '*player.youku.*', + '*syndication.twitter.com/*', + '*youtube.com/*', + ] if config_dict["advanced"]["hide_some_image"]: NETWORK_BLOCKED_URLS.append('*.woff') @@ -1887,10 +2041,10 @@ def nodriver_overwrite_prefs(conf): prefs_dict["net"]["network_prediction_options"]=3 prefs_dict["privacy_guide"]={} prefs_dict["privacy_guide"]["viewed"]=True - #prefs_dict["privacy_sandbox"]={} - #prefs_dict["privacy_sandbox"]["first_party_sets_enabled"]=False + prefs_dict["privacy_sandbox"]={} + prefs_dict["privacy_sandbox"]["first_party_sets_enabled"]=False prefs_dict["profile"]={} - prefs_dict["profile"]["cookie_controls_mode"]=1 + #prefs_dict["profile"]["cookie_controls_mode"]=1 prefs_dict["profile"]["default_content_setting_values"]={} prefs_dict["profile"]["default_content_setting_values"]["notifications"]=2 prefs_dict["profile"]["default_content_setting_values"]["sound"]=2 @@ -2017,6 +2171,7 @@ async def main(args): if not is_quit_bot: url, is_quit_bot = await nodriver_current_url(tab) + #print("url:", url) if is_quit_bot: try: @@ -2101,8 +2256,7 @@ async def main(args): pass if 'cityline.com' in url: - await nodriver_cityline_main(tab, url, config_dict) - pass + tab = await nodriver_cityline_main(tab, url, config_dict) softix_family = False if 'hkticketing.com' in url: diff --git a/settings.py b/settings.py index 24ea156..3cd83eb 100644 --- a/settings.py +++ b/settings.py @@ -41,7 +41,7 @@ try: except Exception as exc: pass -CONST_APP_VERSION = "MaxBot (2024.03.31)" +CONST_APP_VERSION = "MaxBot (2024.04.01)" CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" CONST_MAXBOT_CONFIG_FILE = "settings.json" diff --git a/webdriver/Maxbotplus_1.0.0/js/cityline_event_common.js b/webdriver/Maxbotplus_1.0.0/js/cityline_event_common.js deleted file mode 100644 index 1a6e792..0000000 --- a/webdriver/Maxbotplus_1.0.0/js/cityline_event_common.js +++ /dev/null @@ -1,467 +0,0 @@ -var getUrlParameter = function getUrlParameter(sParam) { - var sPageURL = window.location.search.substring(1), - sURLVariables = sPageURL.split('&'), - sParameterName, - i; - - for (i = 0; i < sURLVariables.length; i++) { - sParameterName = sURLVariables[i].split('='); - - if (sParameterName[0] === sParam) { - return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]); - } - } - return false; -}; - -var getI18nMonthYear = function(date) { - let year = date.year; - let month = date.month - 1; - let monthTitles = ['month-title-jan', 'month-title-feb', 'month-title-mar', 'month-title-apr', 'month-title-may', 'month-title-jun', 'month-title-jul', 'month-title-aug', 'month-title-sep', 'month-title-oct', 'month-title-Nov', 'month-title-Dec']; - let monthTitle = monthTitles[month]; - let comma = $.i18n().locale == 'en' ? "," : ","; - return $.i18n(monthTitle) + comma + " " + year; -} - -var getI18nWeek = function(date) { - let weekDayTitles = ['week-title-sun', 'week-title-mon', 'week-title-tue', 'week-title-wed', 'week-title-thu', 'week-title-fri', 'week-title-sat']; - let day = date.weekday%7; - let weekDayTitle = weekDayTitles[day]; - return $.i18n(weekDayTitle); -} - -var getI18nTime = function(date) { - let i18nWeek = getI18nWeek(date); - let hour = date.hour; - let hourTitle = (hour < 10) ? "0" + hour : hour; - let minute = date.minute; - let minuteTitle = (minute < 10) ? "0" + minute : minute; - let comma = $.i18n().locale == 'en' ? "," : ","; - return i18nWeek + comma + " " + hourTitle + ":" + minuteTitle; -} - -var getI18nSrDate = function(date) { - let day = date.day; - let month = date.month - 1; - let year = date.year; - let monthTitles = ['month-title-jan', 'month-title-feb', 'month-title-mar', 'month-title-apr', 'month-title-may', 'month-title-jun', 'month-title-jul', 'month-title-aug', 'month-title-sep', 'month-title-oct', 'month-title-Nov', 'month-title-Dec']; - let monthTitle = $.i18n().locale == 'en' ? $.i18n(monthTitles[month]) : month + 1; - return $.i18n('sr-date-format', day, monthTitle, year); // $1=Day, $2=Month, $3=Year -} - -var getPerfHtml = function(perf) { - let status = perf.status; - let statusTitles = {"AVAILABLE" : null, "LIMIT" : "status-title-limit", "SOLDOUT" : "status-title-soldout"}; - let statusTitle = statusTitles[status]; - let statusValue = statusTitle ? $.i18n(statusTitle) : ""; - let statusHtml = ''; - if(statusValue) { - statusHtml = ' ' + - ' ' + statusValue + ''; - } - - let innerButtonHtml = ''; - let performanceNameField = getDataFieldByLang("performanceName"); - let performanceName = perf[performanceNameField]; - let performanceNameHtml = ' ' + performanceName + ''; - - if(perf.performanceDate){ - let performanceDateTz = DateTime.fromMillis(perf.performanceDate).setZone("UTC+8"); - let performanceDateDisplayFormat = perf.performanceDateDisplayFormat; - let monthYear = getI18nMonthYear(performanceDateTz); - let date = performanceDateTz.day; - let time = (performanceDateDisplayFormat == "DISPLAY_FORMAT_NAME_DATE_TIME") ? getI18nTime(performanceDateTz) : getI18nWeek(performanceDateTz); - let srDate = getI18nSrDate(performanceDateTz); - let monthYearHtml = - '
' + - ' ' + monthYear + ' ' + date + '' + - '
'; - innerButtonHtml += monthYearHtml + - '
' + - ' ' + time +'' + performanceNameHtml + statusHtml + - '
'; - } - else { - innerButtonHtml += ' ' + performanceName + ''+ statusHtml; - } - - let perfId = perf.performanceId; - let isPurchasable = perf.isPurchasable; - let disabledHtml = !isPurchasable || perf.status == 'SOLDOUT' ? 'disabled="disabled"' : ''; - let perfHtml = ''; - - return perfHtml; -} - -let myCalendar = null; -let selDate = null; -var fillCalendar = function(perfData){ - let formattedDatePrefData = perfData.performances.map((item)=>{ - return{ - ...item, - performanceDate: moment(item.performanceDate).format("DD/MM/YYYY") - } - }) - - let formattedDateArr = perfData.performances.map((item)=>{ - if(item.performanceDate){ - return moment(item.performanceDate).format("DD/MM/YYYY") - } - }) - - let min = formattedDatePrefData.find(item =>item.status !== "SOLDOUT").performanceDate; - let max = formattedDatePrefData[formattedDatePrefData.length-1].performanceDate; - - let calendarBox = isMobileFun() ? $('.calendar-box')[0] : $('.calendar-box')[$('.calendar-box').length -1] - let dateBox = isMobileFun() ? $('.date-box')[0] : $('.date-box')[$('.date-box').length -1]; - - $(calendarBox).empty(); - myCalendar = jsCalendar.new(calendarBox, min, { - "monthFormat": "YYYY/##", - "dayFormat": "DDD", - }); - - myCalendar.min(min); - myCalendar.max(max); - - $('.jsCalendar table td').mouseover(function(){ - if(!$(this).hasClass('jsCalendar-previous') && !$(this).hasClass('jsCalendar-next') && !$(this).hasClass('jsCalendar-noPerfDate')){ - let day = $(this)[0].innerText < 10 ? '0'+$(this)[0].innerText : $(this)[0].innerText; - let date = $('.jsCalendar-title-name')[0].innerText + '/' + day; - let formatDate = date.split('/').reverse().join('/') - - let sameDatePref = fillterCurrentDatePrefList(perfData,formattedDatePrefData,formatDate); - let sameDatePrefTimes = [] - sameDatePref.performances.forEach(function(perf) { - if(perf.performanceDate){ - let performanceDateTz = DateTime.fromMillis(perf.performanceDate).setZone("UTC+8"); - let time = (perf.performanceDateDisplayFormat == "DISPLAY_FORMAT_NAME_DATE_TIME") ? getI18nTime(performanceDateTz) : getI18nWeek(performanceDateTz); - let getTime = time.split(', ')[1] ? time.split(', ')[1] : time.split(', ')[1]; - let getEventName = $('#eventName').text() ? $('#eventName').text() : $('.item-title:visible').text(); - sameDatePrefTimes.push( getTime + ' ' + getEventName + '
'); - } - }) - let title = sameDatePrefTimes.join('') - $(this).attr('title', title); - $(this).attr('data-toggle', 'tooltip'); - $(this).attr('data-placement', 'top'); - $(this).attr('data-html', true); - $(this).tooltip('show'); - } - }); - - myCalendar.onDateClick(function(event,date){ - const formatDate = jsCalendar.tools.dateToString(date, "DD/MM/yyyy"); - - let curClickMonth = formatDate.split('/')[1]; - let curDisplayMonth = $('.jsCalendar-title-name')[0].innerText.split('/')[1]; - let isCurMonth = curClickMonth == curDisplayMonth ? true : false; - - selDate = formatDate; - if(formattedDateArr.indexOf(formatDate)!== -1 && isCurMonth){ - myCalendar.clearselect(); - - if($('.jsCalendar-selected').length){ - toSelDate = null; - $('.jsCalendar-selected')[0].classList.remove('jsCalendar-selected') - } - myCalendar.select(formatDate); - fillterCurrentDatePrefList(perfData,formattedDatePrefData,formatDate) - dateBox.classList.remove("d-none") - - } - }) - - let toSelDate = null; - if (selectedPerfId) { - toSelDate = formattedDatePrefData.find(i => i.performanceId == selectedPerfId).performanceDate; - myCalendar.goto(toSelDate) - myCalendar.select(toSelDate) - }else{ - myCalendar.goto(selDate); - selDate ? myCalendar.select(selDate) : myCalendar.select(min); - } - - myCalendar.onDateRender(function(date, element, info) { - const formatDate = jsCalendar.tools.dateToString(date, "DD/MM/yyyy"); - - element.classList.remove('jsCalendar-soldout') - - if(formattedDateArr.indexOf(formatDate) === -1){ - element.classList.add('jsCalendar-noPerfDate') - } - - let obj = {}; - let newArr = []; - formattedDatePrefData.forEach(item => { - if (!obj[item.performanceDate]) { - var arr = []; - arr.push(item); - newArr.push(arr); - obj[item.performanceDate] = item; - } else { - newArr.forEach(function (value, index) { - if (value[0].performanceDate == item.performanceDate) { - value.push(item) - } - }) - } - }) - - let soldoutDateArr = [] - newArr.forEach(item =>{ - if(item.every(i => i.status == "SOLDOUT")){ - item.forEach(i => { - if(soldoutDateArr.indexOf(i.performanceDate) == -1){ - soldoutDateArr.push(i.performanceDate) - } - }) - } - }) - - if(soldoutDateArr.indexOf(formatDate) !== -1){ - element.classList.add('jsCalendar-soldout') - } - - if(document.querySelector('.jsCalendar-selected')!== null && document.querySelector('.jsCalendar-current')!== null){ - document.querySelector('.jsCalendar-current').classList.remove('jsCalendar-current') - } - - if(element.classList.contains('jsCalendar-selected')){ - let sameDatePref = fillterCurrentDatePrefList(perfData,formattedDatePrefData,formatDate) - fillPerformanceData(sameDatePref) - postConstruct() - } - - }); - myCalendar.refresh(); - - changePerfCalendarTheme(); - changePerfCalendarLang(); -} - -var fillterCurrentDatePrefList = function(perfData,formattedDatePrefData,curDate){ - let sameDatePerfIdArr = [] - formattedDatePrefData.forEach(i =>{ - if(i.performanceDate === curDate){ - return sameDatePerfIdArr.push(i.performanceId) - } - }) - - let sameDatePref = {} - sameDatePref.performances = [] - perfData.performances.forEach(pref =>{ - sameDatePerfIdArr.forEach(id =>{ - if(pref.performanceId === id){ - sameDatePref.performances.push(pref) - } - }) - }) - return sameDatePref; -} - -var changePerfCalendarTheme = function(){ - if(Cookies.get('cl-theme-color') == 'black'){ - document.querySelector('.jsCalendar').classList.remove('grey-theme') - document.querySelector('.jsCalendar').classList.add('black-theme') - }else if(Cookies.get('cl-theme-color') == 'night'){ - document.querySelector('.jsCalendar').classList.remove('black-theme') - document.querySelector('.jsCalendar').classList.add('grey-theme') - }else{ - document.querySelector('.jsCalendar').classList.remove('black-theme') - document.querySelector('.jsCalendar').classList.remove('grey-theme') - } -} - -var changePerfCalendarLang = function(){ - if(get_lang() !== 'en'){ - myCalendar.setLanguage("zh") - }else{ - myCalendar.setLanguage("en") - } -} - -var handleEventNotAvail = function() { - let html = '
' + $.i18n("event-not-available-msg") + "
"; - $(".main").html(html); - $("footer").addClass("fixed-bottom"); -} - - -var utsvEventListCache = null; -var eventLikeListCache = null; -var isExpired = function(expiry) { - return (new Date(expiry) < new Date()); -} -var getClUtsvEventByUtsvId = function(utsvId) { - var result = (!utsvEventListCache) ? null : - utsvEventListCache.filter(function(val, i) { - return (val.utsvId == utsvId); - }); - return (result) ? result[0]: null; -} -var getLikeCountById = function(evtId) { - var clEvt = getClUtsvEventByUtsvId(evtId); - var jsonCount = (clEvt) ? clEvt.likeCount : 0; - var cookieCount = (clEvt) ? Cookies.get('cl-like-' + clEvt.id) || 0 : 0; - return Math.max(jsonCount, cookieCount); -} -var isLikedEvent = function(evtId) { - var clEvt = getClUtsvEventByUtsvId(evtId); - // var cookieLike = (clEvt) ? Cookies.get('cl-like-' + clEvt.id) || 0 : 0; - // var result = (eventLikeListCache && clEvt) ? eventLikeListCache.indexOf(clEvt.id) : null; - // return (cookieLike || result >= 0); - let result - if(isCitylineLogin){ - result = (eventLikeListCache && clEvt) ? eventLikeListCache.indexOf(clEvt.id) : null; - return result !== null && result >= 0 - }else{ - var list = JSON.parse(localStorage.getItem("not-login-like-utsvEvent")); - result = (list && clEvt) ? list.indexOf(clEvt.id) : null; - return result !== null && result >= 0 - } -} -var drawLikeButton = function(evtId) { - var likeCount = getLikeCountById(evtId); - if(likeCount || likeCount == 0) - $('.likeCount').text(likeCount); - - if(isLikedEvent(evtId)) - $('.likeIcon').addClass('liked'); - else - $('.likeIcon').removeClass('liked'); - - if(getClUtsvEventByUtsvId(evtId)) $('#likeButton').show(); -} -var getLatestClUtsvEventList = function() { - // var url = citylineDomainUrl+'/api/utsvEventList.do'; - var url = citylineDomainUrl+'/data/utsvEventList.json'; - return $.get({url: url, global: false}, function(data, status) { - if(data && data.utsvEventList) { - utsvEventListCache = data.utsvEventList; - utsvEventListCache = utsvEventListCache.map(function(etv) { - var newEvt = {}; - newEvt['id'] = etv.id; - newEvt['utsvId'] = etv.utsvId; - newEvt['likeCount'] = etv.likeCount; - newEvt['synonym'] = etv.synonym; - return newEvt; - }); - var expiry = 15; // in minutes - var localList = { - utsvEventListCache, - 'expiry': new Date(new Date().getTime() + (expiry*60*1000)).getTime() - } - localStorage.setItem("like-count-utsvEvent", JSON.stringify(localList)); - - var eventId = getUrlParameter('event'); - drawLikeButton(eventId); - } - }).fail(function(){ - // console.log("failed to call /api/utsvEventList.do"); - console.log("failed to call /data/utsvEventList.json"); - }); -} -var getClUtsvEventList = function() { - var deferred = $.Deferred(); - var list = JSON.parse(localStorage.getItem('like-count-utsvEvent')); - if (!list || (list.expiry && isExpired(list.expiry))) { - return getLatestClUtsvEventList(); - } else { - utsvEventListCache = list.utsvEventListCache; - var eventId = getUrlParameter('event'); - drawLikeButton(eventId); - - return deferred; - } -} -var getLatestEventLikeList = function() { - var url = citylineDomainUrl + '/api/customer/favourite.do'; - return $.get({ - url: url, - global: false, - xhrFields: { - withCredentials: true - } - }, function(data, status) { - if(data && data.utsvEventIds) { - eventLikeListCache = data.utsvEventIds; - var expiry = 15; // in minutes - var localList = { - 'likeList': eventLikeListCache, - 'expiry': new Date(new Date().getTime() + (expiry*60*1000)).getTime() - } - if(isCitylineLogin){ - localStorage.setItem("like-list-utsvEvent", JSON.stringify(localList)); - } - var eventId = getUrlParameter('event'); - drawLikeButton(eventId); - } - }).fail(function(){ - console.log("failed to call /api/customer/favourite.do"); - }); -} -var getEventLikeList = function() { - var deferred = $.Deferred(); - var likeListJson = JSON.parse(localStorage.getItem('like-list-utsvEvent')); - if (!likeListJson || (likeListJson.expiry && isExpired(likeListJson.expiry))) { - return getLatestEventLikeList(); - } else { - eventLikeListCache = likeListJson.likeList; - var eventId = getUrlParameter('event'); - drawLikeButton(eventId); - - return deferred; - } -} -var setupLikeFeature = function() { - $.when(getClUtsvEventList()) - .then(getEventLikeList()); -} -var doLikeThisEvent = function(evtId) { - var clEvt = getClUtsvEventByUtsvId(evtId); - var isLiked =isLikedEvent(evtId); - if(clEvt && !isLiked) { - var url = citylineDomainUrl + '/api/customer/favourite/utsvEvent/' + clEvt.id + '.do'; - console.log('like!', 'utsvId: ' + evtId, 'revamp id: ' + clEvt.id); - return $.post({ - url: url, - xhrFields: { - withCredentials: true - }, - global: false - }, function(data, status, xhr){ - var clEvtId = clEvt.id - var expiry = 60; // in minutes - var expires = new Date(new Date().getTime() + (expiry*60*1000)); - - if(isCitylineLogin){ - - if(Cookies.get('cl-like-' + clEvt.id)){ - var likeCount = +Cookies.get('cl-like-' + clEvt.id) + 1; - }else{ - var likeCount = clEvt.likeCount + 1; - } - - getLatestEventLikeList() - }else{ - var likeCount = clEvt.likeCount + 1; - var notLoginLikeList = JSON.parse(localStorage.getItem("not-login-like-utsvEvent") || "[]"); - notLoginLikeList.push(clEvtId); - localStorage.setItem("not-login-like-utsvEvent",JSON.stringify(notLoginLikeList)) - } - Cookies.set('cl-like-' + clEvtId, likeCount, { expires }); - drawLikeButton(evtId); - return true; - }).fail(function() { - return false; - }); - } -} -/* -var url = contextPath + "/[activityCode]/performance?event=[eventId]&perfId=[perfId]"; -url = url.replace("[activityCode]",activityCode) - .replace("[eventId]", eventId) - .replace("[perfId]",selectedPerfId) -location.href = url; -*/ \ No newline at end of file diff --git a/webdriver/Maxbotplus_1.0.0/js/cityline_event_detail.js b/webdriver/Maxbotplus_1.0.0/js/cityline_event_detail.js index 515dda2..0eeff62 100644 --- a/webdriver/Maxbotplus_1.0.0/js/cityline_event_detail.js +++ b/webdriver/Maxbotplus_1.0.0/js/cityline_event_detail.js @@ -1,347 +1,18 @@ -const storage = chrome.storage.local; -var settings = null; +$("#eventLargeCoverUrl").remove(); +$("#s_footer").remove(); +$("footer").remove(); -var eventDataCache = null; -var performanceDataCache = null; -var selectedPerfId = null; -var perfPriceListMap = null; -var pageLoaded = false; -var eventImageUrl = null; -var perfDisplayStyle = null; -var allPerformanceDataCache = null; -var contextPath = "/utsvInternet"; - -var showEnlargedImage = function(image){ - if(image === 'event'){ - $('.image').attr('src', eventImageUrl); - } - $("#commonImageModal").modal('show'); -} - -var addToCalendar = function() { - if(eventDataCache && eventDataCache.eventDate){ - let addToCalButton= document.querySelector('add-to-calendar-button') - - localStorage.getItem('theme-color') == 'black'? addToCalButton.setAttribute('lightMode','dark') : addToCalButton.removeAttribute('lightMode') - - let options = []; - options.push('Google|'+ $.i18n("calendar-google")) - options.push('iCal|'+ $.i18n("calendar-ical")) - options.push('Outlook.com|'+ $.i18n("calendar-outlook")) - addToCalButton.setAttribute('options',JSON.stringify(options)) - - let customLabels = { - 'close': $.i18n("calendar-close"), - 'label.addtocalendar': $.i18n("calendar-label-addtocalendar") - }; - addToCalButton.setAttribute('customLabels',JSON.stringify(customLabels)) - - let venueNameField = getDataFieldByLang("venueName") - addToCalButton.setAttribute('location',eventDataCache.venue[venueNameField]) - - $("#addToCal").show(); - - if(performanceDataCache){ - if(performanceDataCache.performances && performanceDataCache.performances.length > 0) { - let dates = [] - performanceDataCache.performances.forEach(perf =>{ - let performanceNameField = getDataFieldByLang("performanceName"); - let performanceName = perf[performanceNameField]; - - if(performanceDataCache.performances.length == 1){ - addToCalButton.setAttribute('name', performanceName) - addToCalButton.setAttribute('startDate', moment(perf.performanceDate).format("YYYY-MM-DD")) - }else{ - let prefDate = { - name: performanceName, - startDate: moment(perf.performanceDate).format("YYYY-MM-DD") - } - dates.push(prefDate) - } - }) - - if(performanceDataCache.performances.length > 1) addToCalButton.setAttribute('dates',JSON.stringify(dates)) - - } - } - } -} - -var fillEventData = function(data) { - console.log("eventData:", data); - eventDataCache = data; - eventImageUrl = data.eventLargeCoverUrl - - let reload=false; - let eventStatues = {"TOBESOLD" : "event-status-tobesold", "SALE" : "event-status-sale", "SOLDOUT" : "event-status-soldout", "EXPIRED" : "event-status-expired"}; - if(data.status=="TOBESOLD") reload=true; - if(data.status=="SOLDOUT") reload=true;; - - if(reload) { - let auto_reload_page_interval = 0.0; - if(settings) { - auto_reload_page_interval = settings.advanced.auto_reload_page_interval; - } - if(auto_reload_page_interval == 0) { - //console.log('Start to reload now.'); - location.reload(); - } else { - console.log('We are going to reload after few seconeds.'); - setTimeout(function () { - location.reload(); - }, auto_reload_page_interval * 1000); - } - } - -} - -var openWindow = function(url) { - let citylineWindow = window.open(url,"_blank ","width=1020,height=600,top=0,left=20,resizable=yes,menubar=no,scrollbars=yes,status=yes"); - citylineWindow.focus(); -} - -var fillPerformanceData = function(data) { - //console.log("eventPerfData:", data); - performanceDataCache = data; - perfPriceListMap = new Map(); - //selectedPerfId = null; - let perfHtml = ""; - if(data.performances && data.performances.length > 0) { - - let fillerPerId = []; - data.performances.forEach(i => fillerPerId.push(i.performanceId)) - - data.performances.forEach(function(perf, i) { - perfHtml += getPerfHtml(perf) - perfPriceListMap.set(perf.performanceId, perf.pricelist); - - if(perfDisplayStyle === 'DEFAULT'){ - if(!selectedPerfId && perf.status != 'SOLDOUT') selectedPerfId = perf.performanceId; - }else if(perfDisplayStyle === 'CALENDAR'){ - if(!selectedPerfId && perf.status != 'SOLDOUT') selectedPerfId = perf.performanceId; - - if(!fillerPerId.includes(+selectedPerfId)){ - if(perf.status != 'SOLDOUT') selectedPerfId = perf.performanceId; - } - - } - - /* Google Analytics */ - var formatDate = new Date(perf.performanceDate); - var item = { - id : "[" + eventSynonym + "] " + formatForGoogleAnalytics(formatDate), // 2021/08/14 23:59 (Sat) - name : event_en, - category : "[" + eventSynonym + "] " + formatForGoogleAnalytics(formatDate), - list_position : i - }; - viewItems.push(item); - - if (i == 0) { - googleAnalyticViewItem(perf.performanceId, formatForGoogleAnalytics(perf.performanceDate)); - } - }); - - googleAnalyticViewItemList(); - - $(".date-box").html(perfHtml); - selectPerf(); - - } - else { - $(".date-title").addClass("d-none"); - } -} - -var getPerfById = function(perfId) { - var perfList = performanceDataCache.performances; - if(perfList && perfList.length > 0) { - return perfList.find(perf => perf.performanceId == perfId) - } else { - return null; - } -} - -var fillPriceList = function(perfId) { - let priceList = perfPriceListMap.get(perfId); - let ticketPriceHtml = getTicketPriceHtml(priceList); - $(".puchase-bottom").html(ticketPriceHtml); -} - -var selectPerf = function() { - if(selectedPerfId){ - $('button.date-time-position').attr("aria-pressed", false); - let selectedElement = $("*[data-perf-id='" + selectedPerfId + "']"); - selectedElement.addClass("item-onclick"); - selectedElement.attr("aria-pressed", true); - fillPriceList(selectedPerfId); - - var perf = getPerfById(selectedPerfId); - if (perf) { - var perfDate = new Date(perf.performanceDate); - googleAnalyticViewItem(selectedPerfId, formatForGoogleAnalytics(perfDate)); - } - } -} - -var getTicketPriceHtml = function(priceList){ - let ticketPriceHtml = ""; - if(priceList){ - priceList.sort((a, b) => (a.price > b.price) ? -1 : 1); - priceList.forEach(function(pl) { - let statusHtml = ""; - if(pl.status == 'LIMIT' || pl.status == 'SOLDOUT'){ - statusHtml = ''; - } - ticketPriceHtml += ' '; - }); - } - - ticketPriceHtml = '
' + - '
' + $.i18n("price-title" ) + '
' + - '
'+ ticketPriceHtml + '
' + - '
' + - '
' + - ' ' + - '
'; - - return ticketPriceHtml; - -} - -var postConstruct = function(){ - $(".date-time-position").click(function(){ - $('button.date-time-position').attr("aria-pressed", false); - $(".item-onclick").removeClass("item-onclick"); - $(this).addClass("item-onclick"); - $(this).attr("aria-pressed", true); - let perfId = $(this).data("perf-id"); - selectedPerfId = perfId; - fillPriceList(perfId); - setPurchaseBtnClick(); - }); - - $('#likeButton').on('click', function() { - var eventId = getUrlParameter('event'); - if(doLikeThisEvent(eventId)) - $('.likeIcon').addClass('liked'); - }) - - setPurchaseBtnClick(); - if (needToPurchase) { - $(".purchase-btn").click(); - } - - // hide presenter if repeated - if($("[data-i18n=event-presenter]").text() == $("#firstDesc div p:first-child").text()) { - $("[data-i18n=event-presenter]").parent().hide(); - } -} - - -var purchaseBtnClick = function() { - $.LoadingOverlay("show"); - var eventId = getUrlParameter('event'); - var url = contextPath + "/internet/performance?event=[eventId]&perfId=[perfId]"; - url = url.replace("[eventId]", eventId) - .replace("[perfId]",selectedPerfId) - location.href = url; - $.LoadingOverlay("close"); -} - -var setPurchaseBtnClick = function() { - $(".purchase-btn").click(function () { - if(hasLoggedIn){ - purchaseBtnClick(); - } - else { - var addParams = []; - if(selectedPerfId) - addParams.push('perfId=' + selectedPerfId); - //console.log('addParams', addParams) - loginCallback = purchaseBtnClick; - login(true, addParams); - } - }); -} - -var reloadFromCache = function() { - fillEventData(eventDataCache); - if(perfDisplayStyle === 'DEFAULT'){ - fillPerformanceData(performanceDataCache); - }else if(perfDisplayStyle === 'CALENDAR'){ - fillCalendar(allPerformanceDataCache) - } - postConstruct(); -} - -var loadArchiveUrl = function(archiveUrl) { - $.ajax({ - type : "GET", - dataType: "json", - url: archiveUrl, - async: false, - global: false, - cache: true, - success: function(data) { - fillEventData(data); - }, - statusCode: { - 403: function() { - handleEventNotAvail(); - } - }, - }); -} - -var loadData = function() { +function dom_ready() { let eventId = getUrlParameter('event'); - if(eventId){ - let eventRequestUrl = contextPath + "/internet/api/event/" + eventId; - let eventPerfRequestUrl = contextPath + "/internet/api/event/" + eventId + "/performances"; - return $.when($.getJSON(eventRequestUrl)).then(function(data){ - if(data.eventId) fillEventData(data); - else if (data.archiveUrl){ - //$(".date-title").addClass("d-none"); - loadArchiveUrl(data.archiveUrl); - } - else handleEventNotAvail(); - - perfDisplayStyle = data.performancesDisplayStyle; - return $.getJSON(eventPerfRequestUrl); - }).then(function(data){ - allPerformanceDataCache = data; - }); - } - else { - console.log("no event specified"); - } + //let selectedPerfId = 71202; + var url = contextPath + "/[activityCode]/performance?event=[eventId]&perfId=[perfId]"; + url = url.replace("[activityCode]",activityCode) + .replace("[eventId]", eventId) + .replace("[perfId]",selectedPerfId) + //console.log(url); + //location.href = url; } -function cityline_event_status_check() -{ - selectedPerfId = getUrlParameter('perfId'); - if(pageLoaded) { - reloadFromCache(); - }else{ - pageLoaded = true; - loadData(); - } -} +// not able to redirt, must click reCAPTCAH button. +// dom_ready(); -storage.get('settings', function (items) -{ - if (items.settings) - { - settings = items.settings; - } -}); - -storage.get('status', function (items) -{ - if (items.status && items.status=='ON') - { - cityline_event_status_check(); - } else { - console.log('no status found'); - } -}); diff --git a/webdriver/Maxbotplus_1.0.0/js/cityline_msg_front.js b/webdriver/Maxbotplus_1.0.0/js/cityline_msg_front.js index 82b25ba..f769173 100644 --- a/webdriver/Maxbotplus_1.0.0/js/cityline_msg_front.js +++ b/webdriver/Maxbotplus_1.0.0/js/cityline_msg_front.js @@ -25,10 +25,10 @@ function begin() //retry(); //console.log("trigger"); $(".eventposter").off(); - setRetryUrl(window.location.href); + if (typeof setRetryUrl !== "undefined") { + setRetryUrl(window.location.href); + } $(".btn_cta").prop('disabled', false); - if (ddsScheduler != undefined) - clearInterval(ddsScheduler); //$(".btn_cta").prop('disabled', false).trigger("click"); if (typeof goEvent !== "undefined") { if(location.href.indexOf('home?') > -1) { @@ -91,7 +91,6 @@ setInterval(() => { SetItem(ItemType.Local, ""); }, 100); - function getHtmlDocName() { var pathname = location.pathname; var pathParts = pathname.split('/'); @@ -102,7 +101,6 @@ function getHtmlDocName() { if(getHtmlDocName()==null) { history.back(); } -$(".eventposter").off(); if (typeof goEvent !== "undefined") { if(location.href.indexOf('home?') > -1) { //goEvent(); @@ -110,3 +108,4 @@ if (typeof goEvent !== "undefined") { history.back(); } } + diff --git a/webdriver/Maxbotplus_1.0.0/js/cityline_performance.js b/webdriver/Maxbotplus_1.0.0/js/cityline_performance.js new file mode 100644 index 0000000..9951b46 --- /dev/null +++ b/webdriver/Maxbotplus_1.0.0/js/cityline_performance.js @@ -0,0 +1,100 @@ +const storage = chrome.storage.local; +var settings = null; + +function cityline_area_keyword(settings) +{ + let area_keyword_array = []; + if(settings) { + if(settings.area_auto_select.area_keyword.length > 0) { + if(settings.area_auto_select.area_keyword!='""') { + area_keyword_array = JSON.parse('[' + settings.area_auto_select.area_keyword +']'); + } + } + } + + //console.log(area_keyword_array); + let target_area = null; + let matched_block=[]; + let query_string = "div.price > div.form-check"; + if(area_keyword_array.length) { + for (let i = 0; i < area_keyword_array.length; i++) { + $(query_string).each(function () + { + let html_text=$(this).text(); + //console.log("html_text:"+html_text); + if(html_text.indexOf('售罄')>-1) { + // do nothing. + } else { + if(html_text.indexOf(area_keyword_array[i])>-1) { + matched_block.push($(this)); + } + } + target_area = get_target_area_with_order(settings, matched_block); + }); + + if (matched_block.length) { + console.log("match keyword:" + area_keyword_array[i]); + break; + } + } + } else { + $(query_string).each(function () + { + let html_text=$(this).text(); + //console.log("html_text:"+html_text); + if(html_text.indexOf('售罄')>-1) { + // do nothing. + } else { + matched_block.push($(this)); + } + }); + target_area = get_target_area_with_order(settings, matched_block); + } + + if (target_area) { + target_area.find("input").click(); + } else { + console.log("not target_area found.") + } +} + +function cityline_performance() +{ + //console.log("cityline_performance"); + if(settings) { + cityline_area_keyword(settings); + + $("#ticketType0").val(settings.ticket_number); + + if(settings.advanced.disable_adjacent_seat) { + $('input[type=checkbox]:checked').each(function() { + $(this).click(); + }); + } + } + + setTimeout(() => { + cityline_performance() + }, "500"); +} + +storage.get('settings', function (items) +{ + if (items.settings) + { + settings = items.settings; + } +}); + +storage.get('status', function (items) +{ + if (items.status && items.status=='ON') + { + cityline_performance(); + } else { + console.log('no status found'); + } +}); + +$("#s_footer").remove(); +$("footer").remove(); diff --git a/webdriver/Maxbotplus_1.0.0/js/kktix_registrations_assign.js b/webdriver/Maxbotplus_1.0.0/js/kktix_registrations_assign.js index 0e74129..4cb4171 100644 --- a/webdriver/Maxbotplus_1.0.0/js/kktix_registrations_assign.js +++ b/webdriver/Maxbotplus_1.0.0/js/kktix_registrations_assign.js @@ -56,9 +56,10 @@ function kktix_area_keyword(settings, base_info, register_info) // console.log(area_keyword_array); let target_area = null; let matched_block=[]; + let query_string = "div.ticket-unit"; if(area_keyword_array.length) { for (let i = 0; i < area_keyword_array.length; i++) { - $("div.ticket-unit").each(function () + $(query_string).each(function () { let html_text=$(this).text(); if(html_text.indexOf(area_keyword_array[i])>-1) { @@ -73,7 +74,7 @@ function kktix_area_keyword(settings, base_info, register_info) } } } else { - $("div.ticket-unit").each(function () + $(query_string).each(function () { matched_block.push($(this)); }); diff --git a/webdriver/Maxbotplus_1.0.0/manifest.json b/webdriver/Maxbotplus_1.0.0/manifest.json index cd80e79..0c8a9cd 100644 --- a/webdriver/Maxbotplus_1.0.0/manifest.json +++ b/webdriver/Maxbotplus_1.0.0/manifest.json @@ -338,17 +338,19 @@ "https://*.cityline.com/utsvlnternet/*/login?lang=TW" ], "run_at": "document_end", + "world": "MAIN", "js": [ - "jquery.min.js", - "js/cityline_event_common.js" + "js/cityline_event_detail.js" ] }, { "matches": [ "https://shows.cityline.com/tc/*", - "https://priority.cityline.com/tc/*", "https://shows.cityline.com/en/*", - "https://priority.cityline.com/en/*" + "https://priority.cityline.com/tc/*", + "https://priority.cityline.com/en/*", + "https://cultural.cityline.com/tc/*", + "https://cultural.cityline.com/en/*" ], "run_at": "document_end", "world": "MAIN", @@ -357,6 +359,17 @@ "js/cityline_shows_buy_front.js" ] }, + { + "matches": [ + "https://venue.cityline.com/utsvInternet/*/performance?*" + ], + "run_at": "document_end", + "js": [ + "jquery.min.js", + "js/common.js", + "js/cityline_performance.js" + ] + }, { "matches": [ "https://ticketplus.com.tw/activity/*"