From 173dedbf4127eb216fbf5f4f46d5f9389f9e1897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CSamoilenkoVadym=E2=80=9D?= <“samoylenko.vadym@gmail.com”> Date: Fri, 14 Feb 2025 11:57:46 +0000 Subject: [PATCH] Initial commit --- .DS_Store | Bin 0 -> 6148 bytes Book1 copy.xlsx | Bin 0 -> 14241 bytes Book1 copy_updated.xlsx | Bin 0 -> 14132 bytes Book1.xlsx | Bin 0 -> 20732 bytes Book1_updated.xlsx | Bin 0 -> 5524 bytes Solventum_2.code-workspace | 7 + config.json | 1 + cookies.json | 297 +++++++++++++++++++++++++++++ main.py | 376 +++++++++++++++++++++++++++++++++++++ main_backup.py | 201 ++++++++++++++++++++ zshrc | 3 + 11 files changed, 885 insertions(+) create mode 100644 .DS_Store create mode 100644 Book1 copy.xlsx create mode 100644 Book1 copy_updated.xlsx create mode 100644 Book1.xlsx create mode 100644 Book1_updated.xlsx create mode 100644 Solventum_2.code-workspace create mode 100644 config.json create mode 100644 cookies.json create mode 100644 main.py create mode 100644 main_backup.py create mode 100644 zshrc diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 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%0AhPAWQA0haxui73V(fJKu7o)HGH z*wIjVL${b4&!wdan&XGs&8Iz>a&SE(nqZu!CX0ASShjFr`ExGqp`fe^PT)Hhf-v4p z4(f8A=0|rTctfBtJjT=_vWN`A9DvPznLR~;O0R2u@KJrZPl+9^CF&*Tcm+u_tL#cN z6O$wZHh1;UJaSdmSXEYko@#L&m?cAuA4`nGX5-IW)zC{glQc0Jtm@tGAJH%;>>Mz+ z4zZbS-Krb__9f~tp1`X(c&21CiIXVE51Gf{ItblHimaADzQ*!I|ly& zQM11kijO3gmp&SnzCUHj8tca$>p)jp!K^7$LME#n8%=htnM2kpmdR{zIU`R>FOxW)HxQAdRDY-dQ=`Sx0!-Azi94db93-~bcyA#9FtKuiUwlnB8JKucSl1laoWf- zjbi~(LAI+X6@qLu7nD)N@h$ZI;rH@tm+EyNmSLNbF_g-kLRc=AtOGXqlclE80vzdFEI2K zhQ?uN28I>^^h℞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 literal 0 HcmV?d00001 diff --git a/Book1.xlsx b/Book1.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5f70b28dc5ab2bf4dec6e1f0c9a77856aaa274d5 GIT binary patch literal 20732 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 literal 0 HcmV?d00001 diff --git a/Book1_updated.xlsx b/Book1_updated.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..649d4746b1029626a8bc743da23321ec94bce6a9 GIT binary patch literal 5524 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 SHvoVDeM_TjyzDRK4e%fO+^s?Y literal 0 HcmV?d00001 diff --git a/Solventum_2.code-workspace b/Solventum_2.code-workspace new file mode 100644 index 0000000..362d7c2 --- /dev/null +++ b/Solventum_2.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "." + } + ] +} \ No newline at end of file diff --git a/config.json b/config.json new file mode 100644 index 0000000..c5d3242 --- /dev/null +++ b/config.json @@ -0,0 +1 @@ +{"last_dir": "/Users/vadymsamoilenko/Documents/GIT/Script"} \ No newline at end of file diff --git a/cookies.json b/cookies.json new file mode 100644 index 0000000..2c426d8 --- /dev/null +++ b/cookies.json @@ -0,0 +1,297 @@ +[ + { + "domain": ".adobe.com", + "expirationDate": 1773416846.396066, + "hostOnly": false, + "httpOnly": false, + "name": "AMCV_9E1005A551ED61CA0A490D45%40AdobeOrg", + "path": "/", + "sameSite": "unspecified", + "secure": false, + "session": false, + "storeId": "0", + "value": "1176715910%7CMCMID%7C17349451639425099143064126811155089188%7CMCAAMLH-1739461646%7C6%7CMCAAMB-1739461646%7CRKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y%7CMCOPTOUT-1738864046s%7CNONE%7CMCAID%7CNONE%7CvVersion%7C5.4.0", + "id": 1 + }, + { + "domain": ".adobe.com", + "hostOnly": false, + "httpOnly": false, + "name": "AMCVS_9E1005A551ED61CA0A490D45%40AdobeOrg", + "path": "/", + "sameSite": "unspecified", + "secure": false, + "session": true, + "storeId": "0", + "value": "1", + "id": 2 + }, + { + "domain": ".adobe.com", + "expirationDate": 1770323817.206102, + "hostOnly": false, + "httpOnly": true, + "name": "aux_sid", + "path": "/", + "sameSite": "no_restriction", + "secure": true, + "session": false, + "storeId": "0", + "value": "ARveyFS2d5-rYByIEKNVQNpPLmxTkVev8z6gJDDB0ZK3yAi7FR2pZ99q-CmiaFoeNAv305oPWfwjN1EM7ZknomKJpsNtCzz_5gS6ynKMEFQIThpefdkgPIIi2ID43fyqB_hp7llLxEKha_MiNJAf7xQI9jC30p-tLpN4nG3Xyw3R_BuZMphR333c6cgH39UeUcmioemcKJjqBVKahqun1U5IUHzlhnwqwu5vJ04x7FF7Q-qW5py22Yv9vC5QZplCPcjrFQgMlRUzUuA2sJ1tmA0j0aAD9bigzuMf32MYE8bra1H07PxPUMcV5LsKhe8cWP_0WzhD05p2dVAQI5Pp3O1E8J-i6RCf3uX_ehbqCpDPaJMzj_F4av6yFchvCjgsPOFhakXWxKnvuJWd_TeOJ0kgF5K2tMGEUKL6V4m7wCriM3zXHfG83cZMATeCcLoQtB8BvcP-dMOJvRKvVha3bN0oM7cauMSBiA5OQdm2rprMqJxX6VrGlh7t1Ozr7IvszMt91SO8EH8U3jCzkYL32ttvAkHGDjHfz-PZNWMMVkAGpgJO4JYPZphtZJllB54NH_1WO8iX5vAJ2T-qOpWQwmbLYqKQbcRt6Sb7AxvpEuRuFURHSxRfZQrGOKUIkzstiAI-LHOZOAL7Fhoa-NB9r0lqWY9cVas2kGjqUvEoIAXFJaLW1pGrXu3XpiPZcFWYTNyg1MvL4nkFm4i4VyLlQcFJnXosGSU3JmTch4o71cm4QwHvCEuzMF1mGkIr3ruhZkrXUrXZVhtbJu6XjNcebNUxCF69ecy-lUbVZOw7WOcwBY4", + "id": 3 + }, + { + "domain": ".adobe.com", + "expirationDate": 1738858648, + "hostOnly": false, + "httpOnly": false, + "name": "gpv", + "path": "/", + "sameSite": "unspecified", + "secure": false, + "session": false, + "storeId": "0", + "value": "Account:IMS:Process:Complete", + "id": 4 + }, + { + "domain": ".adobe.com", + "expirationDate": 1770392846, + "hostOnly": false, + "httpOnly": false, + "name": "OptanonConsent", + "path": "/", + "sameSite": "no_restriction", + "secure": true, + "session": false, + "storeId": "0", + "value": "isGpcEnabled=0&datestamp=Thu+Feb+06+2025+15%3A47%3A26+GMT%2B0000+(Greenwich+Mean+Time)&version=202311.1.0&browserGpcFlag=0&isIABGlobal=false&hosts=&consentId=e40ce7eb-a167-4f1e-a646-2783e554a9c1&interactionCount=1&landingPath=NotLandingPage&groups=C0001%3A1%2CC0002%3A0%2CC0003%3A0%2CC0004%3A0&AwaitingReconsent=false", + "id": 5 + }, + { + "domain": ".adobe.com", + "hostOnly": false, + "httpOnly": false, + "name": "s_cc", + "path": "/", + "sameSite": "unspecified", + "secure": false, + "session": true, + "storeId": "0", + "value": "true", + "id": 6 + }, + { + "domain": ".adobe.com", + "expirationDate": 1773416848.218817, + "hostOnly": false, + "httpOnly": false, + "name": "s_ecid", + "path": "/", + "sameSite": "unspecified", + "secure": false, + "session": false, + "storeId": "0", + "value": "MCMID%7C17349451639425099143064126811155089188", + "id": 7 + }, + { + "domain": ".adobe.com", + "expirationDate": 1773416845.222818, + "hostOnly": false, + "httpOnly": false, + "name": "s_fid", + "path": "/", + "sameSite": "unspecified", + "secure": false, + "session": false, + "storeId": "0", + "value": "2959E3DDB076BFB0-013B63E267B41648", + "id": 8 + }, + { + "domain": ".adobe.com", + "hostOnly": false, + "httpOnly": true, + "name": "s_ims", + "path": "/", + "sameSite": "no_restriction", + "secure": true, + "session": true, + "storeId": "0", + "value": "https://ims-na1.adobelogin.com/ims/session/v1/ZTQxMzZlZWQtZmIyNC00YjVhLTk0YjItZDZjZmNlZWJlZWJmLS02RDk2MUU5MTY3NjVENzREMEE0OTVFRTNAZWZhNTNkZmY2NDQ5MzZiZTQ5NWZiMi5l", + "id": 9 + }, + { + "domain": ".adobe.com", + "hostOnly": false, + "httpOnly": false, + "name": "s_ppv", + "path": "/", + "sameSite": "unspecified", + "secure": false, + "session": true, + "storeId": "0", + "value": "[%22auth.services.adobe.com/en_US/deeplink.html%22%2C100%2C0%2C1199%2C2544%2C1199%2C2560%2C1440%2C2%2C%22P%22]", + "id": 10 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "hostOnly": true, + "httpOnly": false, + "name": "ApplicationGatewayAffinity", + "path": "/", + "sameSite": "unspecified", + "secure": false, + "session": true, + "storeId": "0", + "value": "773965041c0c59ebea497d34b646d89f", + "id": 11 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "hostOnly": true, + "httpOnly": false, + "name": "ApplicationGatewayAffinityCORS", + "path": "/", + "sameSite": "no_restriction", + "secure": true, + "session": true, + "storeId": "0", + "value": "773965041c0c59ebea497d34b646d89f", + "id": 12 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "expirationDate": 1773326870.932259, + "hostOnly": true, + "httpOnly": false, + "name": "bp-system-notifications", + "path": "/", + "sameSite": "unspecified", + "secure": false, + "session": false, + "storeId": "0", + "value": "uid-e4ea986f4acffba136080287c5412be6e039ae8d", + "id": 13 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "expirationDate": 1739461692, + "hostOnly": true, + "httpOnly": false, + "name": "cq-assets-files", + "path": "/", + "sameSite": "unspecified", + "secure": false, + "session": false, + "storeId": "0", + "value": "card", + "id": 14 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "expirationDate": 1739371666.692624, + "hostOnly": true, + "httpOnly": false, + "name": "cq-authoring-mode", + "path": "/", + "sameSite": "unspecified", + "secure": true, + "session": false, + "storeId": "0", + "value": "TOUCH", + "id": 15 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "hostOnly": true, + "httpOnly": true, + "name": "JSESSIONID", + "path": "/", + "sameSite": "unspecified", + "secure": true, + "session": true, + "storeId": "0", + "value": "gzkyrt1sverd1v2izhudp0zqc", + "id": 16 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "hostOnly": true, + "httpOnly": true, + "name": "login-token", + "path": "/", + "sameSite": "unspecified", + "secure": true, + "session": true, + "storeId": "0", + "value": "b373b976-515c-44af-a48f-f88f93e9f8c7%3ad07ac9e0-74e4-4a85-a003-b9a3398c999a_18d4b4f70b20d06d108d03bbdf0c7333%3acrx.default", + "id": 17 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "hostOnly": true, + "httpOnly": true, + "name": "MC_AoD2", + "path": "/", + "sameSite": "unspecified", + "secure": true, + "session": true, + "storeId": "0", + "value": "\"{9e5029df170e469714ac05a728d40da7fbb935fa88f0b39f13b7357f913b50db5fac90a34db3ca79403bca01d8ba5c820537af63204ce1f5ed5109354e312786f6e435a5746586c5d2f98dfdbb5938a0226ba3bd1d0e281fb6a774040ff4b8a72934968c0f699390f02dad020914edb4921b5e80653550aec6366fe401e47c06}\"", + "id": 18 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "hostOnly": true, + "httpOnly": true, + "name": "oauth-authid", + "path": "/", + "sameSite": "unspecified", + "secure": true, + "session": true, + "storeId": "0", + "value": "ims", + "id": 19 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "hostOnly": true, + "httpOnly": true, + "name": "oauth-configid", + "path": "/", + "sameSite": "unspecified", + "secure": true, + "session": true, + "storeId": "0", + "value": "ims", + "id": 20 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "hostOnly": true, + "httpOnly": false, + "name": "renderid", + "path": "/", + "sameSite": "unspecified", + "secure": true, + "session": true, + "storeId": "0", + "value": "rend0", + "id": 21 + }, + { + "domain": "mmmspinco.brand-portal.adobe.com", + "hostOnly": true, + "httpOnly": false, + "name": "shell.omnisearch.results.layoutId", + "path": "/", + "sameSite": "unspecified", + "secure": false, + "session": true, + "storeId": "0", + "value": "card", + "id": 22 + } + ] \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..a5323d6 --- /dev/null +++ b/main.py @@ -0,0 +1,376 @@ +import json +import os +import re +import time +import logging +from datetime import datetime +import openpyxl +from kivy.app import App +from kivy.properties import ObjectProperty +from kivy.uix.label import Label +from kivy.uix.button import Button +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.popup import Popup +from kivy.uix.progressbar import ProgressBar +from kivy.uix.filechooser import FileChooserListView +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.action_chains import ActionChains +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.common.exceptions import NoSuchElementException, TimeoutException, StaleElementReferenceException +from colorama import Fore, Style, init + +init(autoreset=True) +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + filename=f'app_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log' +) + +CONFIG_FILE = 'config.json' +CHROME_PROFILE_PATH = "/Users/vadymsamoilenko/Library/Application Support/Google/Chrome/Profile 1" +PORTAL_URL = "https://mmmspinco.brand-portal.adobe.com" +WAIT_TIMEOUT = 30 +LONG_TIMEOUT = 60 +MAX_RETRIES = 3 +SEARCH_DELAY = 3 + +def get_last_used_directory(): + if os.path.exists(CONFIG_FILE): + with open(CONFIG_FILE, 'r') as file: + config = json.load(file) + return config.get('last_dir', '') + return '' + +def save_last_used_directory(directory): + with open(CONFIG_FILE, 'w') as file: + json.dump({'last_dir': directory}, file) + +def normalize_string(s): + return re.sub(r'[-_\s]+', '_', s.lower().strip()) + +def get_search_key(filename): + if not filename: + return "" + base = os.path.splitext(filename)[0] + return base.replace("-", "_") + +class FileSearchApp(App): + file_path = ObjectProperty(None) + + def __init__(self): + super().__init__() + self.setup_logging() + self.driver: webdriver.Chrome | None = None + self.continue_button = None + self.progress = None + self.status_label = None + self.label = None + + def setup_logging(self): + self.logger = logging.getLogger(__name__) + + def build(self): + self.file_path = "" + self.extensions = [".psd", ".indd", ".tif", ".tiff"] + + layout = BoxLayout(orientation='vertical') + self.label = Label(text="Select an Excel file with Asset IDs") + layout.add_widget(self.label) + + # Создаем кнопки с использованием on_press вместо bind + choose_button = Button(text="Choose File", on_press=self.select_file) + layout.add_widget(choose_button) + + start_button = Button(text="Open Login Page", on_press=self.open_login_page) + layout.add_widget(start_button) + + self.continue_button = Button( + text="Continue After Login", + disabled=True, + on_press=self.start_search + ) + layout.add_widget(self.continue_button) + + self.progress = ProgressBar(max=100) + layout.add_widget(self.progress) + + self.status_label = Label(text="Ready") + layout.add_widget(self.status_label) + + return layout + + def select_file(self, instance): + last_dir = get_last_used_directory() or '.' + content = BoxLayout(orientation='vertical') + filechooser = FileChooserListView(path=last_dir, filters=['*.xlsx']) + + def on_selection(instance, selection, touch=None): + if selection: + self.on_file_select(selection, popup) + + filechooser.bind(selection=on_selection) + content.add_widget(filechooser) + + popup = Popup( + title="Choose Excel File", + content=content, + size_hint=(0.9, 0.9) + ) + popup.open() + + def on_file_select(self, selection, popup): + if selection: + self.file_path = selection[0] + self.label.text = f"Selected File: {self.file_path}" + self.logger.info(f"Selected file: {self.file_path}") + save_last_used_directory(os.path.dirname(self.file_path)) + popup.dismiss() + else: + self.logger.warning("No file selected.") + + def wait_for_element(self, by, value, timeout=WAIT_TIMEOUT, retries=3): + if self.driver is None: + raise ValueError("WebDriver is not initialized") + + for attempt in range(retries): + try: + element = WebDriverWait(self.driver, timeout).until( + EC.presence_of_element_located((by, value)) + ) + return element + except TimeoutException: + if attempt == retries - 1: + raise + time.sleep(2) + return None + + def wait_for_search_results(self, timeout=LONG_TIMEOUT): + if self.driver is None: + return False + + try: + WebDriverWait(self.driver, timeout).until( + EC.presence_of_element_located((By.ID, "granite-omnisearch-result")) + ) + time.sleep(SEARCH_DELAY) + return True + except TimeoutException: + return False + + def open_login_page(self, instance): + if not self.file_path: + popup = Popup( + title='Warning', + content=Label(text='Select a file before starting!'), + size_hint=(0.8, 0.3) + ) + popup.open() + return + + try: + options = Options() + options.add_argument(f"user-data-dir={CHROME_PROFILE_PATH}") + self.driver = webdriver.Chrome(options=options) + + if self.driver is not None: + self.driver.get(f"{PORTAL_URL}/mediaportal.html/content/dam/mac/mmmspinco") + time.sleep(5) + + if self.wait_for_element(By.XPATH, "/html/body/coral-shell/coral-shell-content/div[1]/a/img"): + self.continue_button.disabled = False + self.logger.info("Login successful, ready to continue.") + login_popup = Popup( + title='Login', + content=Label(text='Please log in and complete 2FA.\nClick "Continue After Login" once logged in.'), + size_hint=(0.8, 0.3) + ) + login_popup.open() + except Exception as e: + self.logger.error(f"Error opening login page: {e}") + if self.driver: + self.driver.quit() + + def find_matching_link(self, file_name, psd_links): + try: + normalized_search_key = normalize_string(file_name) + self.logger.info(f"Looking for links matching: {normalized_search_key}") + + best_match = None + best_ratio = 0 + + for link in psd_links if isinstance(psd_links, list) else [psd_links]: + try: + href = link.get_attribute("href") + if href: + link_filename = os.path.splitext(href.split('/')[-1])[0] + normalized_link = normalize_string(link_filename) + + if normalized_search_key in normalized_link or normalized_link in normalized_search_key: + ratio = len(set(normalized_search_key.split('_')) & set(normalized_link.split('_'))) / \ + len(set(normalized_search_key.split('_')) | set(normalized_link.split('_'))) + + if ratio > best_ratio: + best_ratio = ratio + best_match = href + self.logger.info(f"Found better match: {href} (ratio: {ratio})") + + except Exception as e: + self.logger.error(f"Error processing link: {e}") + continue + + return best_match if best_match and best_ratio >= 0.5 else None + + except Exception as e: + self.logger.error(f"Error finding PSD links: {e}") + return None + + def process_row(self, row, total_rows): + if self.driver is None: + raise ValueError("WebDriver is not initialized") + + if not row or not hasattr(row[0], 'value'): + return None, None + + asset_id = row[0].value + file_name = row[2].value if len(row) >= 3 else None + found_link = None + + if not asset_id or not file_name: + return row[0].row if hasattr(row[0], 'row') else None, None + + self.status_label.text = f"Processing {asset_id}" + self.logger.info(f"Processing Asset ID: {asset_id} with filename: {file_name}") + + for attempt in range(MAX_RETRIES): + try: + self.driver.get(f"{PORTAL_URL}/aem/search.html") + time.sleep(SEARCH_DELAY) + + search_box = WebDriverWait(self.driver, WAIT_TIMEOUT).until( + EC.presence_of_element_located((By.CSS_SELECTOR, "input[name='fulltext']")) + ) + search_box.clear() + search_box.send_keys(asset_id) + search_box.send_keys(Keys.RETURN) + + WebDriverWait(self.driver, LONG_TIMEOUT).until( + EC.presence_of_element_located((By.ID, "granite-omnisearch-result")) + ) + time.sleep(SEARCH_DELAY) + + asset_element = WebDriverWait(self.driver, WAIT_TIMEOUT).until( + EC.presence_of_element_located(( + By.XPATH, + f"//coral-card-subtitle[contains(@class, 'foundation-collection-item-subtitle') and text()='{file_name}']" + )) + ) + + if asset_element: + asset_card = asset_element.find_element(By.XPATH, "./ancestor::coral-card") + self.driver.execute_script("arguments[0].scrollIntoView(true);", asset_card) + time.sleep(1) + + self.driver.execute_script(""" + var element = arguments[0]; + var rect = element.getBoundingClientRect(); + var event = new MouseEvent('mouseover', { + 'view': window, + 'bubbles': true, + 'cancelable': true, + 'clientX': rect.left + rect.width/2, + 'clientY': rect.top + rect.height/2 + }); + element.dispatchEvent(event); + """, asset_card) + time.sleep(1) + + properties_button = WebDriverWait(self.driver, 10).until( + EC.element_to_be_clickable((By.CSS_SELECTOR, "button[title='Properties']")) + ) + self.driver.execute_script("arguments[0].click();", properties_button) + time.sleep(2) + + psd_links = WebDriverWait(self.driver, LONG_TIMEOUT).until( + EC.presence_of_all_elements_located(( + By.XPATH, + "//div[contains(@class, 'references-referencing')]//a[contains(@data-asset-path, '.psd')]" + )) + ) + + if psd_links: + found_link = self.find_matching_link(file_name, psd_links) + if found_link: + break + else: + self.logger.warning(f"Asset card not found for {asset_id}") + + except Exception as e: + self.logger.error(f"Error processing {asset_id} (attempt {attempt + 1}): {e}") + if attempt == MAX_RETRIES - 1: + break + time.sleep(2) + + if hasattr(row[0], 'row'): + progress = (row[0].row / total_rows) * 100 if total_rows > 0 else 0 + self.progress.value = progress + + return row[0].row if hasattr(row[0], 'row') else None, found_link + + def start_search(self, instance): + if not self.file_path or self.continue_button.disabled: + popup = Popup( + title='Warning', + content=Label(text='Ensure you are logged in before starting!'), + size_hint=(0.8, 0.3) + ) + popup.open() + return + + try: + wb = openpyxl.load_workbook(self.file_path) + if wb is None: + raise ValueError("Failed to load workbook") + + sheet = wb.active + if sheet is None: + raise ValueError("Failed to get active sheet") + + total_rows = sheet.max_row - 1 if sheet.max_row > 1 else 1 + + for row in sheet.iter_rows(min_row=2, max_row=sheet.max_row): + try: + row_num, found_link = self.process_row(row, total_rows) + if row_num is not None: + sheet.cell(row=row_num, column=2, value=found_link if found_link else "Links not found") + save_path = self.file_path.replace(".xlsx", "_updated.xlsx") + wb.save(save_path) + except Exception as e: + self.logger.error(f"Error processing row: {e}") + continue + + self.logger.info("Processing completed") + success_popup = Popup( + title='Success', + content=Label(text=f"Processing completed. File saved."), + size_hint=(0.8, 0.3) + ) + success_popup.open() + + except Exception as e: + self.logger.error(f"Error during search: {e}") + error_popup = Popup( + title='Error', + content=Label(text=f"An error occurred: {str(e)}"), + size_hint=(0.8, 0.3) + ) + error_popup.open() + finally: + if self.driver: + self.driver.quit() + +if __name__ == '__main__': + FileSearchApp().run() \ No newline at end of file diff --git a/main_backup.py b/main_backup.py new file mode 100644 index 0000000..8914dd7 --- /dev/null +++ b/main_backup.py @@ -0,0 +1,201 @@ +import json +import os +import time +import openpyxl +from kivy.app import App +from kivy.uix.label import Label +from kivy.uix.button import Button +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.popup import Popup +from kivy.uix.filechooser import FileChooserListView +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +from selenium.common.exceptions import NoSuchElementException, TimeoutException + +# Файл конфигурации для сохранения последнего пути +CONFIG_FILE = 'config.json' + +def get_last_used_directory(): + """Возвращает последний использованный каталог из файла конфигурации.""" + if os.path.exists(CONFIG_FILE): + with open(CONFIG_FILE, 'r') as file: + config = json.load(file) + return config.get('last_dir', '') + return '' + +def save_last_used_directory(directory): + """Сохраняет последний использованный каталог в файл конфигурации.""" + with open(CONFIG_FILE, 'w') as file: + json.dump({'last_dir': directory}, file) + +def get_search_key(filename): + """ + Преобразует имя файла: удаляет расширение и заменяет дефисы на подчёркивания. + Например, "3M-Protemp4-Banner-900x450-BG.jpg" превращается в "3M_Protemp4_Banner_900x450_BG". + """ + if not filename: + return "" + base = os.path.splitext(filename)[0] + return base.replace("-", "_") + +class FileSearchApp(App): + def build(self): + self.file_path = "" + self.extensions = [".psd", ".indd", ".tif", ".tiff"] + + layout = BoxLayout(orientation='vertical') + self.label = Label(text="Select an Excel file with Asset IDs") + layout.add_widget(self.label) + + choose_button = Button(text="Choose File") + choose_button.bind(on_press=self.select_file) + layout.add_widget(choose_button) + + start_button = Button(text="Open Login Page") + start_button.bind(on_press=self.open_login_page) + layout.add_widget(start_button) + + self.continue_button = Button(text="Continue After Login", disabled=True) + self.continue_button.bind(on_press=self.start_search) + layout.add_widget(self.continue_button) + + return layout + + def select_file(self, instance): + last_dir = get_last_used_directory() or '.' + filechooser = FileChooserListView(path=last_dir, filters=['*.xlsx']) + popup = Popup(title="Choose Excel File", content=filechooser, size_hint=(0.9, 0.9)) + filechooser.bind(on_submit=lambda chooser, selection, touch: self.on_file_select(selection, popup)) + popup.open() + + def on_file_select(self, selection, popup): + if selection: + self.file_path = selection[0] + self.label.text = f"Selected File: {self.file_path}" + print(f"Selected file: {self.file_path}") + save_last_used_directory(os.path.dirname(self.file_path)) + popup.dismiss() + else: + print("No file selected.") + + def open_login_page(self, instance): + if not self.file_path: + popup = Popup(title='Warning', + content=Label(text='Select a file before starting!'), + size_hint=(0.8, 0.3)) + popup.open() + return + options = Options() + options.add_argument("user-data-dir=/Users/vadymsamoilenko/Library/Application Support/Google/Chrome/Profile 1") + self.driver = webdriver.Chrome(options=options) + try: + self.driver.get("https://mmmspinco.brand-portal.adobe.com/mediaportal.html/content/dam/mac/mmmspinco") + time.sleep(5) + WebDriverWait(self.driver, 30).until( + EC.presence_of_element_located((By.XPATH, "/html/body/coral-shell/coral-shell-content/div[1]/a/img")) + ) + self.continue_button.disabled = False + print("Login successful, ready to continue.") + login_popup = Popup(title='Login', + content=Label(text='Please log in and complete 2FA.\nClick "Continue After Login" once logged in.'), + size_hint=(0.8, 0.3)) + login_popup.open() + except Exception as e: + print("Error opening login page:", e) + self.driver.quit() + + def start_search(self, instance): + if not self.file_path or self.continue_button.disabled: + popup = Popup(title='Warning', + content=Label(text='Ensure you are logged in before starting!'), + size_hint=(0.8, 0.3)) + popup.open() + return + try: + wb = openpyxl.load_workbook(self.file_path) + sheet = wb.active + + # Предполагаем, что: + # - Столбец 1: Asset ID + # - Столбец 3: Имя файла (с расширением) + for row in sheet.iter_rows(min_row=2, max_row=sheet.max_row): + asset_id = row[0].value # Asset ID + file_name = row[2].value if len(row) >= 3 else None # Имя файла + found_link = None + if asset_id and file_name: + search_key = get_search_key(file_name) + print(f"Processing Asset ID: {asset_id} with search key: {search_key}") + + self.driver.get("https://mmmspinco.brand-portal.adobe.com/aem/search.html") + search_box = WebDriverWait(self.driver, 10).until( + EC.presence_of_element_located((By.NAME, "fulltext")) + ) + # Очистка поля ввода через clear() и JavaScript + time.sleep(3) + search_box.clear() + self.driver.execute_script("arguments[0].value = '';", search_box) + + # Поиск по asset_id для первоначального отбора + search_box.send_keys(asset_id) + search_box.send_keys(Keys.RETURN) + time.sleep(3) + + try: + properties_button = WebDriverWait(self.driver, 30).until( + EC.element_to_be_clickable((By.XPATH, "//button/coral-icon[@icon='infoCircle']")) + ) + properties_button.click() + time.sleep(3) + + # Получаем все PSD-ссылки из секции "Others" + psd_link_elements = WebDriverWait(self.driver, 30).until( + EC.presence_of_all_elements_located( + (By.XPATH, "//div[contains(@class, 'references-referencing')]//a[@data-relation='others' and contains(@data-asset-path, '.psd')]") + ) + ) + time.sleep(3) + # Выводим отладочную информацию для каждого кандидата + for elem in psd_link_elements: + title_attr = elem.get_attribute("title") + href = elem.get_attribute("href") + print(f"Candidate element -> title: {title_attr}, href: {href}") + # Выбираем элемент, где search_key встречается в title или href (без учета расширения) + for elem in psd_link_elements: + title_attr = elem.get_attribute("title") + href = elem.get_attribute("href") + search_key_lower = search_key.lower() + if (search_key_lower in title_attr.lower() if title_attr else False) or \ + (search_key_lower in href.lower() if href else False): + found_link = href + print(f"Selected link matching search key: {found_link}") + break + except TimeoutException: + print("Timeout while waiting for the PSD link element.") + found_link = None + except NoSuchElementException: + print("PSD link element not found.") + found_link = None + except Exception as e: + print(f"Unexpected error occurred: {e}") + found_link = None + + if not found_link: + print("No suitable link found for asset:", asset_id) + + sheet.cell(row=row[0].row, column=2, value=found_link if found_link else "Links not found") + print(f"Processed asset {asset_id}, link: {found_link}") + save_path = self.file_path.replace(".xlsx", "_updated.xlsx") + wb.save(save_path) + success_popup = Popup(title='Success', + content=Label(text=f"File saved: {save_path}"), + size_hint=(0.8, 0.3)) + success_popup.open() + finally: + self.driver.quit() + +if __name__ == '__main__': + FileSearchApp().run() \ No newline at end of file diff --git a/zshrc b/zshrc new file mode 100644 index 0000000..6765014 --- /dev/null +++ b/zshrc @@ -0,0 +1,3 @@ +export PATH="/opt/homebrew/opt/tcl-tk/bin:$PATH" +export LDFLAGS="-L/opt/homebrew/opt/tcl-tk/lib" +export CPPFLAGS="-I/opt/homebrew/opt/tcl-tk/include"