listing-facebook/auto-listing-facebook-marke.../src/services/thief.service.ts

191 lines
5.1 KiB
TypeScript

class ThiefService {
base64ToFile(base64: string, filename: string, mimeType: string): File {
// Nếu có tiền tố "data:image/xxx;base64," thì cắt bỏ
const pureBase64 = base64.includes(",") ? base64.split(",")[1] : base64;
const byteString = atob(pureBase64);
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
const blob = new Blob([ab], { type: mimeType });
return new File([blob], filename, { type: mimeType });
}
clickByPoint(el: Element) {
const rect: DOMRect = el.getBoundingClientRect();
const x: number = rect.left + rect.width / 2;
const y: number = rect.top + rect.height / 2;
const target: Element | null = document.elementFromPoint(x, y);
if (target) {
target.dispatchEvent(
new MouseEvent("click", {
bubbles: true,
cancelable: true,
view: window,
})
);
}
}
async getElementByXPath(
xpath: string,
retryCount: number = 3,
delay: number = 400
): Promise<HTMLElement | null> {
return new Promise((resolve) => {
let attempts = 0;
const tryFind = () => {
const el: Node | null = document.evaluate(
xpath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
if (el instanceof HTMLElement) {
resolve(el);
return;
}
attempts++;
if (attempts < retryCount) {
setTimeout(tryFind, delay);
} else {
resolve(null);
}
};
tryFind();
});
}
async imageUrlToBase64(url: string): Promise<string> {
const response = await fetch(url);
const blob = await response.blob();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => {
if (typeof reader.result === "string") {
// Kết quả là data URL (base64)
resolve(reader.result.split(",")[1]);
} else {
reject("Không thể đọc dữ liệu ảnh");
}
};
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}
getImageExtension(url: string): string | null {
try {
const pathname = new URL(url).pathname; // Lấy phần path từ URL
const match = pathname.match(/\.([a-zA-Z0-9]+)$/); // Tìm đuôi file
return match ? match[1].toLowerCase() : null;
} catch {
// Nếu url không hợp lệ thì fallback sang split
const parts = url.split("?");
const path = parts[0];
const match = path.match(/\.([a-zA-Z0-9]+)$/);
return match ? match[1].toLowerCase() : null;
}
}
imageLocalToBase64(relativePath: string): Promise<string> {
return new Promise((resolve, reject) => {
try {
// Lấy URL đầy đủ trong extension
const url = chrome.runtime.getURL(`${relativePath}`);
// Fetch file
fetch(url)
.then((res) => res.blob())
.then((blob) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result as string); // base64
reader.onerror = reject;
reader.readAsDataURL(blob);
})
.catch(reject);
} catch (err) {
reject(err);
}
});
}
scrollToElement(el: HTMLElement, behavior: ScrollBehavior = "smooth") {
if (!el) return;
el.scrollIntoView({
behavior, // "smooth" hoặc "auto"
block: "center", // Đưa phần tử ra giữa màn hình
inline: "nearest",
});
}
getElementPointCoores(el: HTMLElement): { x: number; y: number } | null {
if (!el) return null;
const rect = el.getBoundingClientRect();
const x = rect.left + rect.width / 2;
const y = rect.top + rect.height / 2;
return { x, y };
}
setInputValue(el: HTMLInputElement | HTMLTextAreaElement, value: string) {
if (!el) return;
// Gán giá trị trực tiếp
el.value = value;
// Tạo và dispatch sự kiện input
el.dispatchEvent(new Event("input", { bubbles: true }));
// Tạo và dispatch sự kiện change (nếu cần)
el.dispatchEvent(new Event("change", { bubbles: true }));
}
writeToInput = async (value: string, xpath: string) => {
const el = (await this.getElementByXPath(xpath)) as HTMLInputElement;
if (!el) throw new Error("Xpath is not found");
// Scroll to EL
this.scrollToElement(el);
this.clickByPoint(el);
this.setInputValue(el, value);
};
pressEnter(el: HTMLElement) {
if (!el) {
throw new Error("Textarea not found:", el);
}
el.focus();
// Chuỗi sự kiện bàn phím
["keydown", "keypress", "keyup"].forEach((type) => {
el.dispatchEvent(
new KeyboardEvent(type, {
key: "Enter",
code: "Enter",
keyCode: 13,
which: 13,
bubbles: true,
cancelable: true,
})
);
});
}
}
export const thiefService = new ThiefService();