Today, if you can't afford a paid Google account, you can use Google Apps Script to create your own tools to help you. Here's an older example of an email manager that labels, groups, deletes emails, etc.

2D, 3D, game, games, online game, game development, game engine, programming, OpenGL, Open AI, math, graphics, design, graphic, graphics, game development, game engine, programming, web development, web art, web graphic, arts, tutorial, tutorials,

function getChannelStats() {
const response = YouTube.Channels.list(
"snippet,statistics",
{ mine: true }
);
const ch = response.items[0];
return {
title: ch.snippet.title,
subs: Number(ch.statistics.subscriberCount),
views: Number(ch.statistics.viewCount),
videos: Number(ch.statistics.videoCount)
};
} ...

// ✅ Chart cu legendă nativă și labelInLegend pentru fiecare serie
// ✅ Chart with native legend and labelInLegend for each series
const chart = chartSheet.newChart()
.setChartType(Charts.ChartType.COMBO)
.addRange(range)
.setPosition(1, 1, 0, 0)
.setOption("title", "BT Funds Evolution Over Time")
.setOption("legend", { position: "right" })
.setOption("width", 1600)
.setOption("height", 900)
.setOption("seriesType", "line")
.setOption("hAxis", { title: "Date" })
.setOption("vAxis", { title: "Value / Return (%)" })
// ✅ LEGENDĂ NATIVĂ CU LABEL IN LEGEND
// ✅ NATIVE LEGEND WITH LABEL IN LEGEND
.setOption("series", {
0: { labelInLegend: "VUAN", color: "#1f77b4", pointSize: 5 },
1: { labelInLegend: "30 zile", color: "#ff7f0e", pointSize: 5 },
2: { labelInLegend: "YTD", color: "#2ca02c", pointSize: 5 },
3: { labelInLegend: "365 zile", color: "#d62728", pointSize: 5 },
4: { labelInLegend: "3 ani", color: "#9467bd", pointSize: 5 }
})

function deleteSheetsWithoutToday() {
// Get today's components (zero-padded and variants)
var now = new Date();
var tz = Session.getScriptTimeZone();
var dd = Utilities.formatDate(now, tz, "dd"); // e.g., "20"
var d = Utilities.formatDate(now, tz, "d"); // e.g., "20" (no leading zero if <10)
var mm = Utilities.formatDate(now, tz, "MM"); // e.g., "11"
var m = Utilities.formatDate(now, tz, "M"); // e.g., "11" (no leading zero if <10)
var yyyy = Utilities.formatDate(now, tz, "yyyy"); // e.g., "2025"
var yy = Utilities.formatDate(now, tz, "yy"); // e.g., "25"
// Build a regex that matches many possible date embeddings in the sheet name
var dateRegex = buildFlexibleDateRegex({ dd: dd, d: d, mm: mm, m: m, yyyy: yyyy, yy: yy });
// Active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var kept = 0;
var deleted = 0;
sheets.forEach(function(sheet) {
var name = sheet.getName();
// If the name contains a combination of today's date components (any of the supported formats), keep it
if (dateRegex.test(name)) {
kept++;
Logger.log("KEEP: " + name);
} else {
ss.deleteSheet(sheet);
deleted++;
Logger.log("DELETE: " + name);
}
});
Logger.log("Summary → Kept: " + kept + ", Deleted: " + deleted);
}
/**
* Build a flexible regex that matches today's date in common formats.
* It covers:
* - dd[sep]mm[sep](yyyy|yy)
* - mm[sep]dd[sep](yyyy|yy)
* - (yyyy|yy)[sep]mm[sep]dd
* - (yyyy|yy)[sep]dd[sep]mm
* - contiguous forms like ddmmyyyy, mmddyyyy, yyyymmdd, ddmmyy, etc.
* - allows multiple separator types: -, _, ., /, space, colon
* - accepts zero-padded and non-padded day/month (e.g., "7" or "07")
*/
function buildFlexibleDateRegex(parts) {
var dd = parts.dd; // zero-padded day
var d = parts.d; // non-padded day
var mm = parts.mm; // zero-padded month
var m = parts.m; // non-padded month
var yyyy = parts.yyyy;
var yy = parts.yy;
// Separator class: one or more of -, _, ., /, space, or colon
var SEP = "[\\-_.\\/\\s:]+";
// Day and month alternatives (padded or not)
var DAY = "(?:" + dd + "|" + d + ")";
var MONTH = "(?:" + mm + "|" + m + ")";
var YEAR = "(?:" + yyyy + "|" + yy + ")";
// Ordered patterns with separators
var withSeps = [
DAY + SEP + MONTH + SEP + YEAR, // dd-mm-yyyy or dd/mm/yy, etc.
MONTH + SEP + DAY + SEP + YEAR, // mm-dd-yyyy
YEAR + SEP + MONTH + SEP + DAY, // yyyy-mm-dd
YEAR + SEP + DAY + SEP + MONTH // yyyy-dd-mm
];
// Contiguous patterns (no separators)
var noSeps = [
dd + mm + yyyy,
dd + mm + yy,
mm + dd + yyyy,
mm + dd + yy,
yyyy + mm + dd,
yy + mm + dd
];
// Optional surrounding non-digit boundaries to avoid matching inside longer numbers
// We’ll use word boundaries plus lookarounds to be more permissive with symbols.
var prefix = "(?<!\\d)"; // no digit before
var suffix = "(?!\\d)"; // no digit after
// Combine all patterns into a single alternation
var combined =
prefix +
"(?:" +
withSeps.join("|") +
"|" +
noSeps.join("|") +
")" +
suffix;
// Make the regex case-insensitive and global
return new RegExp(combined, "i");
}function reseteazaFiltrarea() {
const sheet = SpreadsheetApp.getActiveSheet();
const ultimaLinie = sheet.getLastRow();
sheet.showRows(1, ultimaLinie);
SpreadsheetApp.getUi().alert("Toate rândurile au fost afișate.");
}
function filtreazaRanduriDupaCelulaSelectata() {
const sheet = SpreadsheetApp.getActiveSheet();
const cell = sheet.getActiveCell();
const valoare = cell.getValue();
const coloanaDeFiltrare = cell.getColumn();
const ultimaLinie = sheet.getLastRow();
for (let i = 1; i <= ultimaLinie; i++) {
const valoareRand = sheet.getRange(i, coloanaDeFiltrare).getValue();
sheet.showRows(i); // asigură-te că rândul e vizibil
if (valoareRand !== valoare && i !== cell.getRow()) {
sheet.hideRows(i);
}
}
SpreadsheetApp.getUi().alert(`Filtrare aplicată pentru: ${valoare}`);
}function onOpen() {
// Creează un meniu personalizat în Spreadsheet
var ui = SpreadsheetApp.getUi();
ui.createMenu('Verificare Reclame Blogger')
.addItem('Verifică Reclame', 'checkBloggerAds')
.addItem('Verifică și Trimite Email', 'checkBloggerAdsAndEmail')
.addToUi();
}
function checkBloggerAds() {
// Obține foaia activă
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// Citește datele din coloana A (website-urile)
var range = sheet.getRange("A2:A" + sheet.getLastRow());
var urls = range.getValues();
var results = [];
// Indicatori specifici pentru Google Ads/AdSense pe Blogger
var adsScriptPattern = "adsbygoogle.js"; // Pentru coloana B
var bloggerAdsPatterns = [
"data-ad-client", // Atribut specific AdSense
"google_ad_client", // Folosit în codurile mai vechi sau automate
'class="adsbygoogle"' // Tag-ul <ins> folosit pentru reclame
];
// Verifică fiecare URL
for (var i = 0; i < urls.length; i++) {
var url = urls[i][0];
if (url) { // Verifică dacă URL-ul nu este gol
try {
var response = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
var content = response.getContentText();
var scriptFound = content.includes(adsScriptPattern);
var bloggerAdsFound = false;
// Verifică indicatorii specifici Blogger
for (var j = 0; j < bloggerAdsPatterns.length; j++) {
if (content.includes(bloggerAdsPatterns[j])) {
bloggerAdsFound = true;
break;
}
}
// Adaugă rezultatele pentru coloanele B și C
results.push([scriptFound ? "Da" : "Nu", bloggerAdsFound ? "Da" : "Nu"]);
} catch (e) {
results.push(["Eroare: " + e.message, "Eroare: " + e.message]);
}
} else {
results.push(["", ""]);
}
}
// Scrie rezultatele în coloanele B și C
if (results.length > 0) {
sheet.getRange(2, 2, results.length, 2).setValues(results);
}
}
function checkBloggerAdsAndEmail() {
// Obține foaia activă
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// Citește datele din coloana A (website-urile)
var range = sheet.getRange("A2:A" + sheet.getLastRow());
var urls = range.getValues();
var results = [];
var emailBody = "Rezultatele verificării reclamelor Google Ads pe blogurile Blogger:\n\n";
emailBody += "URL | Script adsbygoogle.js | Implementare Blogger\n";
// Indicatori specifici pentru Google Ads/AdSense pe Blogger
var adsScriptPattern = "adsbygoogle.js"; // Pentru coloana B
var bloggerAdsPatterns = [
"data-ad-client",
"google_ad_client",
'class="adsbygoogle"'
];
// Verifică fiecare URL și construiește corpul email-ului
for (var i = 0; i < urls.length; i++) {
var url = urls[i][0];
if (url) { // Verifică dacă URL-ul nu este gol
try {
var response = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
var content = response.getContentText();
var scriptFound = content.includes(adsScriptPattern);
var bloggerAdsFound = false;
// Verifică indicatorii specifici Blogger
for (var j = 0; j < bloggerAdsPatterns.length; j++) {
if (content.includes(bloggerAdsPatterns[j])) {
bloggerAdsFound = true;
break;
}
}
// Adaugă rezultatele pentru coloanele B și C și la email
results.push([scriptFound ? "Da" : "Nu", bloggerAdsFound ? "Da" : "Nu"]);
emailBody += `${url} | ${scriptFound ? "Da" : "Nu"} | ${bloggerAdsFound ? "Da" : "Nu"}\n`;
} catch (e) {
results.push(["Eroare: " + e.message, "Eroare: " + e.message]);
emailBody += `${url} | Eroare: ${e.message} | Eroare: ${e.message}\n`;
}
} else {
results.push(["", ""]);
}
}
// Scrie rezultatele în coloanele B și C
if (results.length > 0) {
sheet.getRange(2, 2, results.length, 2).setValues(results);
}
// Trimite email-ul
MailApp.sendEmail({
to: "catalinfest@gmail.com",
subject: "Rezultate Verificare Reclame Google Ads pe Blogger",
body: emailBody
});
}/**
* Creates a new Google Docs document with a test link.
* This script is intended to verify the functionality of setLinkUrl and document placement in a folder.
*/
function createDocumentWithTestLink() {
const docTitle = "Document Test Link GAS";
const doc = DocumentApp.create(docTitle); // Creates the initial document in My Drive
const body = doc.getBody(); // Gets the body of the document to add content
// Add a paragraph of text to the document body
const paragraph = body.appendParagraph("This is a test link to Google.");
// Define the test URL (ensure it's a complete URL with protocol, e.g., https://)
const testUrl = "https://www.google.com";
// Set the hyperlink for the entire paragraph
try {
paragraph.setLinkUrl(testUrl); // Applies the URL as a hyperlink to the paragraph
Logger.log(`Link "${testUrl}" was successfully set on the paragraph.`);
} catch (e) {
Logger.log(`Error setting the link: ${e.message}`); // Logs any error during link setting
}
// --- NEW: Move the document to the same folder as the spreadsheet ---
try {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); // Gets the currently active spreadsheet
const spreadsheetFile = DriveApp.getFileById(spreadsheet.getId()); // Gets the Drive file object for the spreadsheet
// Get the parent folder(s) of the spreadsheet. Assumes there is at least one parent folder.
// If the spreadsheet is in the root of My Drive, this might require different handling.
const parentFolders = spreadsheetFile.getParents(); // Gets an iterator for parent folders
if (parentFolders.hasNext()) { // Checks if there is at least one parent folder
const parentFolder = parentFolders.next(); // Gets the first parent folder
DriveApp.getFileById(doc.getId()).moveTo(parentFolder); // Moves the newly created document to the parent folder
Logger.log(`Document "${docTitle}" was moved to folder: ${parentFolder.getName()} (${parentFolder.getUrl()})`);
} else {
// If the spreadsheet has no parent folder (i.e., it's in My Drive root), the document stays in root.
Logger.log(`Spreadsheet "${spreadsheet.getName()}" has no parent folder. The document remains in the root.`);
}
} catch (e) {
Logger.log(`Error moving the document to the folder: ${e.message}`); // Logs any error during folder move
}
// ------------------------------------------------------------------
// Get the URL of the created document and log it
const docUrl = doc.getUrl();
Logger.log(`Document was created: ${docUrl}`);
// Display a notification to the user (will appear in the script editor or logs)
SpreadsheetApp.getUi().alert('Document created', `A new document with a test link has been created. Check the logs for the document URL and its folder.`, SpreadsheetApp.getUi().ButtonSet.OK);
}
/**
* Adds an option to the "Custom Menu" to run the test function.
* This function is automatically called when the Google Sheet is opened.
*/
function onOpen() {
SpreadsheetApp.getUi() // Gets the user interface object for the spreadsheet
.createMenu('Custom Menu') // Creates a new custom menu named "Custom Menu"
.addItem('Create Test Link Document', 'createDocumentWithTestLink') // Adds an item to the menu that calls createDocumentWithTestLink
.addToUi(); // Adds the custom menu to the spreadsheet's UI
}
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Ocazii Scraper')
.addItem('Scrape placa-de-baza', 'scrapeProcess_placa_de_baza')
.addToUi();
}
function scrapeProcess_placa_de_baza() {
const url_placa_de_baza = "https://www.okazii.ro/componente-computere/placa-de-baza/?judete_lp=35&sort=pret_asc";
let html;
try {
const response = UrlFetchApp.fetch(url_placa_de_baza);
html = response.getContentText();
} catch (error) {
Logger.log("Error fetching HTML: " + error.message);
return;
}
const itemRegex = /<div class="list-item[\s\S]*?<h2>[\s\S]*?<a[^>]+href="(.*?)"[^>]+title="(.*?)"[\s\S]*?<span class="prSup"><span>(\d+)<\/span>[\s\S]*?<span class="prList"><span>([\d,]+)<\/span>/g;
const spreadsheetName = "placa_baza_200625";
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheet = spreadsheet.getSheetByName(spreadsheetName) || spreadsheet.insertSheet(spreadsheetName);
// Adaugă headere dacă e un sheet nou
if (sheet.getLastRow() === 0) {
sheet.appendRow(["Data", "Titlu", "Href", "Pret", "Livrare"]);
}
const now = new Date();
const formattedDate = Utilities.formatDate(now, SpreadsheetApp.getActive().getSpreadsheetTimeZone(), "ddMMyy");
let match;
while ((match = itemRegex.exec(html)) !== null) {
let [_, href, title, price, delivery] = match;
delivery = delivery.replace(",", "."); // înlocuiește virgula pentru formatare numerica
const row = [formattedDate, title, href, price, delivery];
sheet.appendRow(row);
}
}
Head batchDeleteEmailSheet Time-Driven May 1, 2025, 11:43:19 PM 158.919 s Completed // try {
// const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// const currentDate = new Date();
// extractedData.forEach((movie, rowIndex) => {
// if (movie.title !== "N/A" && movie.image !== "N/A") {
// const imageFormula = `=IMAGE("${movie.image}")`;
// const rowIndexAdjusted = sheet.getLastRow() + 1;
// sheet.appendRow([currentDate, movie.title, imageFormula, movie.channel, movie.time]);
// sheet.setRowHeight(rowIndexAdjusted, 76); // Set row height to 330px
// }
// });
// Logger.log("Processed movies count: ", extractedData.length);
// } catch (error) {
// Logger.log("Error adding data to spreadsheet: ", error.message);
// }
try {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const currentDate = new Date();
// Formatăm data curentă pentru numele sheet-ului
const formattedDate = Utilities.formatDate(currentDate, SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone(), "yyyy-MM-dd");
const sheetName = `Data-${formattedDate}`;
// Verificăm dacă sheet-ul cu acest nume există deja
let sheet = spreadsheet.getSheetByName(sheetName);
if (!sheet) {
// Creăm un nou sheet dacă nu există
sheet = spreadsheet.insertSheet(sheetName);
}
extractedData.forEach((movie) => {
if (movie.title !== "N/A" && movie.image !== "N/A") {
const imageFormula = `=IMAGE("${movie.image}")`;
const rowIndexAdjusted = sheet.getLastRow() + 1;
sheet.appendRow([currentDate, movie.title, imageFormula, movie.channel, movie.time]);
// Păstrăm formatarea originală pentru înălțimea rândurilor
sheet.setRowHeight(rowIndexAdjusted, 76);
}
});
} catch (error) {
console.error("A apărut o eroare:", error.message);
}function scrapeProcessAndCleanUp() {
const url = "https://www.cinemagia.ro/program-tv/filme-la-tv/filme-pro-tv,antena-1,tvr-1,prima-tv,diva,pro-cinema,film-cafe/azi/";
let html;
try {
const response = UrlFetchApp.fetch(url);
html = response.getContentText();
Logger.log("Fetched HTML content length: ", html.length);
} catch (error) {
Logger.log("Error fetching HTML content: ", error.message);
return;
}
let doc;
try {
doc = DocumentApp.create("Temporary HTML Content");
doc.appendParagraph(html);
doc.saveAndClose();
Logger.log("Document created successfully with ID: ", doc.getId());
} catch (error) {
Logger.log("Error creating/saving document: ", error.message);
return;
}
let text;
try {
const document = DocumentApp.openById(doc.getId());
text = document.getBody().getText();
Logger.log("Document text content length: ", text.length);
} catch (error) {
Logger.log("Error opening document or extracting text: ", error.message);
return;
}
const titles = [...text.matchAll(/<li class="first">(.*?)<\/li>/g)];
const images = [...text.matchAll(/<img src="(https:\/\/static\.cinemagia\.ro\/img\/resize\/db\/movie.*?)"/g)];
const channels = [...text.matchAll(/<span class="r1">(.*?)<\/span>/g)];
const times = [...text.matchAll(/<span class="r2">(.*?)<\/span>/g)];
Logger.log("Titles found: ", titles.length);
Logger.log("Images found: ", images.length);
Logger.log("Channels found: ", channels.length);
Logger.log("Times found: ", times.length);
const extractedData = titles.map((title, index) => {
const image = images[index] ? images[index][1] : "N/A";
const channel = channels[index] ? channels[index][1].trim() : "N/A";
const time = times[index] ? times[index][1].trim() : "N/A";
return {
title: title[1].trim(),
image: image,
channel: channel,
time: time
};
});
try {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const currentDate = new Date();
extractedData.forEach((movie, rowIndex) => {
if (movie.title !== "N/A" && movie.image !== "N/A") {
const imageFormula = `=IMAGE("${movie.image}")`;
const rowIndexAdjusted = sheet.getLastRow() + 1;
sheet.appendRow([currentDate, movie.title, imageFormula, movie.channel, movie.time]);
sheet.setRowHeight(rowIndexAdjusted, 76); // Set row height to 330px
}
});
Logger.log("Processed movies count: ", extractedData.length);
} catch (error) {
Logger.log("Error adding data to spreadsheet: ", error.message);
}
}
/**
* Main function to check files in the root folder and add duplicates to the active spreadsheet
*/
function checkDuplicatesInDrive() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// Clear the sheet and set up headers
sheet.clear();
sheet.appendRow(["Group", "File Name", "Size", "Type", "File Path", "Date Created", "Last Updated", "URL"]);
sheet.getRange(1, 1, 1, 8).setFontWeight("bold").setBackground("#f3f3f3");
// Find all duplicates
const duplicates = findDuplicateFiles(true);
// Check if any duplicates were found
if (Object.keys(duplicates).length === 0) {
sheet.appendRow(["No duplicate files found"]);
sheet.autoResizeColumns(1, 8);
return;
}
// Add duplicates to the sheet
addDuplicatesToSheet(duplicates, sheet);
// Auto-resize columns
sheet.autoResizeColumns(1, 8);
}
/**
* Adds duplicate files to the specified sheet
*/
function addDuplicatesToSheet(duplicates, sheet) {
let groupNumber = 1;
let rowIndex = 2;
let totalDuplicateFiles = 0;
for (const key in duplicates) {
const files = duplicates[key];
totalDuplicateFiles += files.length;
files.forEach((file, index) => {
// Get file path
const filePath = getFilePath(file.id);
sheet.appendRow([
groupNumber,
file.name,
formatFileSize(file.size),
file.mimeType,
filePath,
file.dateCreated.toLocaleString(),
file.lastUpdated.toLocaleString(),
file.url
]);
// Add hyperlink to the file URL
sheet.getRange(rowIndex, 8).setFormula(`=HYPERLINK("${file.url}","Open File")`);
rowIndex++;
});
groupNumber++;
}
// Add summary at the bottom - only if we have duplicates
if (totalDuplicateFiles > 0) {
sheet.appendRow(["SUMMARY"]);
sheet.appendRow([`Found ${totalDuplicateFiles} duplicate files in ${groupNumber - 1} groups.`]);
}
return totalDuplicateFiles;
}
/**
* Gets the file path for a given file ID
*/
function getFilePath(fileId) {
try {
const file = DriveApp.getFileById(fileId);
const parents = file.getParents();
if (parents.hasNext()) {
const parent = parents.next();
return getFolderPath(parent) + "/" + file.getName();
} else {
return "/" + file.getName();
}
} catch (e) {
return "Path not available";
}
}
/**
* Gets the folder path for a given folder
*/
function getFolderPath(folder) {
try {
const parents = folder.getParents();
if (!parents.hasNext()) {
return "/" + folder.getName();
}
const parent = parents.next();
return getFolderPath(parent) + "/" + folder.getName();
} catch (e) {
return "/Unknown";
}
}
/**
* Finds duplicate files in Google Drive based on file size and optionally file type.
* @param {boolean} considerFileType Whether to consider file type when finding duplicates (default: true)
* @param {string} folderId Optional folder ID to search in. If not provided, searches in the entire Drive.
* @return {Object} An object containing groups of duplicate files
*/
function findDuplicateFiles(considerFileType = true, folderId = null) {
// Create a map to store files by their size (and optionally type)
const fileMap = {};
// Get files to check
let files;
if (folderId) {
const folder = DriveApp.getFolderById(folderId);
files = folder.getFiles();
} else {
files = DriveApp.getFiles();
}
// Process each file
while (files.hasNext()) {
const file = files.next();
// Skip Google Docs, Sheets, etc. as they don't have a fixed size
if (file.getSize() === 0) continue;
const fileSize = file.getSize();
const mimeType = file.getMimeType();
// Create a key based on file size and optionally type
let key = fileSize.toString();
if (considerFileType) {
key += '_' + mimeType;
}
// Add file to the map
if (!fileMap[key]) {
fileMap[key] = [];
}
fileMap[key].push({
id: file.getId(),
name: file.getName(),
size: fileSize,
mimeType: mimeType,
url: file.getUrl(),
dateCreated: file.getDateCreated(),
lastUpdated: file.getLastUpdated()
});
}
// Filter out unique files (groups with only one file)
const duplicates = {};
for (const key in fileMap) {
if (fileMap[key].length > 1) {
duplicates[key] = fileMap[key];
}
}
return duplicates;
}
/**
* Alternative function to check files in a specific folder and its subfolders
*/
function checkDuplicatesInFolder() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// Clear the sheet and set up headers
sheet.clear();
sheet.appendRow(["Group", "File Name", "Size", "Type", "File Path", "Date Created", "Last Updated", "URL"]);
sheet.getRange(1, 1, 1, 8).setFontWeight("bold").setBackground("#f3f3f3");
// Collect all files from the folder and subfolders
var fileMap = {};
var rootFolder = DriveApp.getRootFolder(); // Change this to your specific folder if needed
collectFilesFromFolder(rootFolder, fileMap);
// Filter out unique files
const duplicates = {};
for (const key in fileMap) {
if (fileMap[key].length > 1) {
duplicates[key] = fileMap[key];
}
}
// Check if any duplicates were found
if (Object.keys(duplicates).length === 0) {
sheet.appendRow(["No duplicate files found"]);
sheet.autoResizeColumns(1, 8);
return;
}
// Add duplicates to the sheet
addDuplicatesToSheet(duplicates, sheet);
// Auto-resize columns
sheet.autoResizeColumns(1, 8);
}
/**
* Recursively collects files from a folder and its subfolders
*/
function collectFilesFromFolder(folder, fileMap, considerFileType = true) {
// Process files in this folder
var files = folder.getFiles();
while (files.hasNext()) {
const file = files.next();
// Skip Google Docs, Sheets, etc. as they don't have a fixed size
if (file.getSize() === 0) continue;
const fileSize = file.getSize();
const mimeType = file.getMimeType();
// Create a key based on file size and optionally type
let key = fileSize.toString();
if (considerFileType) {
key += '_' + mimeType;
}
// Add file to the map
if (!fileMap[key]) {
fileMap[key] = [];
}
fileMap[key].push({
id: file.getId(),
name: file.getName(),
size: fileSize,
mimeType: mimeType,
url: file.getUrl(),
dateCreated: file.getDateCreated(),
lastUpdated: file.getLastUpdated()
});
}
// Process subfolders
var subfolders = folder.getFolders();
while (subfolders.hasNext()) {
var subfolder = subfolders.next();
collectFilesFromFolder(subfolder, fileMap, considerFileType);
}
}
/**
* Helper function to format file size in a human-readable format
*/
function formatFileSize(bytes) {
if (bytes < 1024) return bytes + " bytes";
else if (bytes < 1048576) return (bytes / 1024).toFixed(2) + " KB";
else if (bytes < 1073741824) return (bytes / 1048576).toFixed(2) + " MB";
else return (bytes / 1073741824).toFixed(2) + " GB";
}
/**
* Creates a new Google Spreadsheet with the duplicate files report
*/
function createDuplicateFilesSpreadsheet() {
const duplicates = findDuplicateFiles(true);
// Create a new spreadsheet
const ss = SpreadsheetApp.create("Duplicate Files Report - " + new Date().toLocaleString());
const sheet = ss.getActiveSheet();
// Set up headers
sheet.appendRow(["Group", "File Name", "Size", "Type", "File Path", "Date Created", "Last Updated", "URL"]);
// Format header row
sheet.getRange(1, 1, 1, 8).setFontWeight("bold").setBackground("#f3f3f3");
// Check if any duplicates were found
if (Object.keys(duplicates).length === 0) {
sheet.appendRow(["No duplicate files found"]);
sheet.autoResizeColumns(1, 8);
return ss.getUrl();
}
// Add duplicates to the sheet
addDuplicatesToSheet(duplicates, sheet);
// Auto-resize columns
sheet.autoResizeColumns(1, 8);
Logger.log(`Spreadsheet created: ${ss.getUrl()}`);
return ss.getUrl();
}
function generateDriveUsageReportPie() {
var drive = DriveApp.getRootFolder();
var files = drive.getFiles();
var data = [['Nume Fișier', 'Dimensiune (KB)']];
while (files.hasNext()) {
var file = files.next();
var fileSizeBytes = file.getSize();
var fileSizeKB = fileSizeBytes / 1024; // Convertim dimensiunea în KB
data.push([file.getName(), fileSizeKB]);
}
// open Google Sheet
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = spreadsheet.getSheetByName('Drive Usage Report');
if (!sheet) {
sheet = spreadsheet.insertSheet('Drive Usage Report');
}
// clean sheet
sheet.clear();
// write values
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
// clean charts from Google Sheets
var charts = sheet.getCharts();
for (var i = 0; i < charts.length; i++) {
sheet.removeChart(charts[i]);
}
// create and add the Pie Chart with all values
var chart = sheet.newChart()
.asPieChart()
.setTitle('Utilizare Google Drive')
.addRange(sheet.getRange(2, 1, data.length - 1, 2)) // Exclude header row
.setPosition(5, 1, 0, 0)
.setOption('title', 'Utilizare Google Drive')
.setOption('legend', {position: 'top'})
.build();
sheet.insertChart(chart);
Logger.log('Raport generat cu succes.');
}

function searchLikedVideos(query) {
if (!query) {
Logger.log('Vă rugăm să furnizați un cuvânt cheie de căutare.');
return;
}
var apiKey = 'YOUR_API_KEY';
var url = 'https://www.googleapis.com/youtube/v3/videos';
url += '?part=snippet';
url += '&myRating=like'; // "Like" filter
url += '&q=' + encodeURIComponent(query); // Cuvântul cheie de căutare
url += '&maxResults=50'; //
var options = {
'method': 'get',
'headers': {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken(),
'X-JavaScript-User-Agent': 'Google Apps Script',
'X-GData-Key': 'key=' + 'YOUR_API_KEY',
'X-YouTube-Client-Name': 'youtubeLikeI', // Numele aplicației dvs.
'X-YouTube-Client-Version': '1.0', // Versiunea aplicației dvs.
'X-YouTube-Developer-Key': 'YOUR_API_KEY',
'X-YouTube-Api-Version': '3',
'X-YouTube-Page-Cl': 'cl=3009377', // Cod unic asociat aplicației dvs.
'X-YouTube-Page-Token': 'token=' + ScriptApp.getOAuthToken(),
'X-YouTube-Utc-Offset': '120', // Offset-ul UTC
'X-YouTube-Time-Zone': 'Europe/Bucharest', // Fusul orar
'X-YouTube-Max-Upload-Rate': '20000', // Rata maximă de încărcare (în KB/s)
'X-YouTube-Max-Download-Rate': '5000000', // Rata maximă de descărcare (în KB/s)
'X-YouTube-Locale': 'ro_RO', // Localizarea dvs.
'X-YouTube-Ad-Format': 'html5_1_adsense2_0'
}
};
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response.getContentText());
if (data.items && data.items.length > 0) {
for (var i = 0; i < data.items.length; i++) {
var channel_ID = data.items[i].snippet.channelId;
Logger.log('Channel Id: ' + channel_ID);
var videoTitle = data.items[i].snippet.title;
Logger.log('Video Title: ' + videoTitle);
}
} else {
Logger.log('Nu s-au găsit videoclipuri "Like" pentru căutarea dată.');
}
}
function search() {
searchLikedVideos('theescapist');
}
function searchByKeyword() {
var results = YouTube.Search.list('id,snippet', {q: 'like', maxResults: 25});
for(var i in results.items) {
var item = results.items[i];
Logger.log('[%s] Title: %s', item.id.videoId, item.snippet.title);
}
}10:20:42 PM Notice Execution started
10:20:45 PM Info Channel Id: UCqg5FCR7NrpvlBWMXdt-5Vg
10:20:45 PM Info Video Title: An Unexpected Dump | Adventure is Nigh! - The Liar, The Witch and The Wartorn | S3 EP 2
10:20:45 PM Info Channel Id: UCXuqSBlHAE6Xw-yeJA0Tunw
10:20:45 PM Info Video Title: Facebook Sold me this Antivirus USB
10:20:45 PM Info Channel Id: UCelXvXZDvx8_TdOOffevzGg
10:20:45 PM Info Video Title: Now You Know with Zac and Jesse: Tesla, EVs, SpaceX, and Twitter
10:20:45 PM Info Channel Id: UCH91ivVTdIPZkhWi6oqeQPQ
10:20:45 PM Info Video Title: There's something INSANE about this..
10:20:45 PM Info Channel Id: UCX0JHmYdFAOr8k8xCvSc0FQ
10:20:45 PM Info Video Title: AI Texture Generator free online, Polycam, seamless texture maker with Blender test render
10:20:45 PM Info Channel Id: UC7Ln337Vpli1JHEFDks1t7g
10:20:45 PM Info Video Title: Signals in Godot are Amazing!
10:20:45 PM Info Channel Id: UCC0_trsvWYyqjZ3njunfU4Q
10:20:45 PM Info Video Title: Memory Management - Unity Tutorial
10:20:45 PM Info Channel Id: UCAvdfiv_vwTH0fw_LHvX21g
10:20:45 PM Info Video Title: ADEVĂRUL despre margarină! Ce spune Sorin Gadola despre ALIMENTELE INTERZISE
10:20:45 PM Info Channel Id: UC6nPUTO22UXVxD8uOei8BjA
10:20:45 PM Info Video Title: Seagate | "Just" a Hard Drive
10:20:45 PM Info Channel Id: UCSojAWUnEUTUcdA9iJ6bryQ
10:20:45 PM Info Video Title: Let's Create Our Character Controller! - Creating a Horror Game in Godot 4 Part 1 C#
10:20:45 PM Info Channel Id: UC1sELGmy5jp5fQUugmuYlXQ
10:20:45 PM Info Video Title: Building a Massive Carousel in Minecraft!
10:20:45 PM Info Channel Id: UCelXvXZDvx8_TdOOffevzGg
10:20:45 PM Info Video Title: Tesla, SpaceX, and Robots, Oh My!
10:20:45 PM Info Channel Id: UCAvdfiv_vwTH0fw_LHvX21g
10:20:45 PM Info Video Title: 3 trucuri pentru înfrânarea poftelor
10:20:45 PM Info Channel Id: UCjCpZyil4D8TBb5nVTMMaUw
10:20:45 PM Info Video Title: Unity Shader Graph - Changing Parameters in Script
10:20:45 PM Info Channel Id: UCggKidH56IZIGQ8SppxYn-Q
10:20:45 PM Info Video Title: iPad apps you NEED😍 digital reading journal | iPad pro & apple pencil
10:20:45 PM Info Channel Id: UCUL9n86w1_MYQmdg-aRhJDg
10:20:45 PM Info Video Title: KeenTools GeoTracker for Blender (Beta)
10:20:45 PM Info Channel Id: UCk-UHW1Q5EBJIHB4jHkVTbA
10:20:45 PM Info Video Title: Samsung NotePaper Screen for Tab S9 tablets (review for writing and drawing)
10:20:45 PM Info Channel Id: UCdWNZCe8NLVuYluV_FdGogA
10:20:45 PM Info Video Title: Gravelbike test TREK ALR 4
10:20:45 PM Info Channel Id: UCUBVVi3dFyBX0B4zUxbrw-Q
10:20:45 PM Info Video Title: Restoration of a rusty 30-year-old MERCEDES T1 bus / Part 1
10:20:45 PM Info Channel Id: UCFkyds8iRRwi64iPrVh_0AA
10:20:45 PM Info Video Title: #121 Protejarea tavanelor din beton chiar daca ai tavan fals
10:20:45 PM Info Channel Id: UCAE8fRq0xXh6gZ6d2EHYipQ
10:20:45 PM Info Video Title: Plajele de la Cercul Polar se bat cu cele din Seychelles! Caniculă în plină vară arctică
10:20:45 PM Info Channel Id: UCelXvXZDvx8_TdOOffevzGg
10:20:45 PM Info Video Title: Why Elon Musk chose Austin, Texas as America's boomtown
10:20:45 PM Info Channel Id: UCjgVg6F0nUF1707kAyzCXVQ
10:20:45 PM Info Video Title: Three USB C Foldable Keyboards With Trackpads
10:20:45 PM Info Channel Id: UC_0CVCfC_3iuHqmyClu59Uw
10:20:45 PM Info Video Title: The YY3568 Is An All New ARM Based SBC : DEV Board That Run Linux Or Android
10:20:45 PM Info Channel Id: UCjgVg6F0nUF1707kAyzCXVQ
10:20:45 PM Info Video Title: Three Folding Keyboards With Usb C
10:20:45 PM Info Channel Id: UCCQWuh2eCjq6K9aY4BrAETA
10:20:45 PM Info Video Title: Lost in a Lava Cave for Days Looking for a Secret Waterfall
10:20:45 PM Info Channel Id: UCKPLvnWhN1Qo51IDDZsmq1g
10:20:45 PM Info Video Title: SparkFun 20th Anniversary: Jennifer Mullins
10:20:45 PM Info Channel Id: UCelXvXZDvx8_TdOOffevzGg
10:20:45 PM Info Video Title: Astronaut Shortage Uncovered: The Surprising Truth
10:20:45 PM Info Channel Id: UCelXvXZDvx8_TdOOffevzGg
10:20:45 PM Info Video Title: How This Gamer Turned Virtual Money into 40K for Wildfire Relief
10:20:45 PM Info Channel Id: UCelXvXZDvx8_TdOOffevzGg
10:20:45 PM Info Video Title: TOP 3 ways a rocket launch can FAIL #starship #rocket #rocketlaunch
10:20:45 PM Info Channel Id: UCelXvXZDvx8_TdOOffevzGg
10:20:45 PM Info Video Title: Elon Musk's superpower
10:20:45 PM Info Channel Id: UCelXvXZDvx8_TdOOffevzGg
10:20:45 PM Info Video Title: I drove the original #tesla #roadster
10:20:45 PM Info Channel Id: UCOALNiNsBtmONJGCw-SCfgA
10:20:45 PM Info Video Title: Godot 4.0: Metadata Demonstration
10:20:45 PM Info Channel Id: UChdrIsYOHZXgEyCLaOHc2Ew
10:20:45 PM Info Video Title: Feţele libertăţii cu Andrei Şerban (@TVR1)
10:20:45 PM Info Channel Id: UCSojAWUnEUTUcdA9iJ6bryQ
10:20:45 PM Info Video Title: Creating a Flexable Level Loading System in Godot 4 C#
10:20:45 PM Info Channel Id: UCA4YUiMFaa3Wn4Rkd1UKFAw
10:20:45 PM Info Video Title: How to create a MENU in Godot 4.1!
10:20:45 PM Info Channel Id: UCTyq5-4JUA_-694Y2pNdYng
10:20:45 PM Info Video Title: Multiplayer in Godot 4 in 3 minutes
10:20:45 PM Info Channel Id: UCTyq5-4JUA_-694Y2pNdYng
10:20:45 PM Info Video Title: API calls in Godot 4 under 4 minutes
10:20:45 PM Info Channel Id: UCr-5TdGkKszdbboXXsFZJTQ
10:20:45 PM Info Video Title: Terrain3D - The New Terrain Engine for Godot
10:20:45 PM Info Channel Id: UCr-5TdGkKszdbboXXsFZJTQ
10:20:45 PM Info Video Title: Godot 4.1 Is Here!
10:20:45 PM Info Channel Id: UClARBYN-cvOBb4DhKKyjo2w
10:20:45 PM Info Video Title: 24) C language. Roguelike: simple AI of monsters. Movement and attack
10:20:45 PM Info Channel Id: UClARBYN-cvOBb4DhKKyjo2w
10:20:45 PM Info Video Title: Tiled GUIDE for developer (level/map editor)
10:20:45 PM Info Channel Id: UClARBYN-cvOBb4DhKKyjo2w
10:20:45 PM Info Video Title: [Solution] Issue with Unity license
10:20:45 PM Info Channel Id: UCX0JHmYdFAOr8k8xCvSc0FQ
10:20:45 PM Info Video Title: Blender Free Addon for Tree Generator - Generate Tree 3D Model
10:20:45 PM Info Channel Id: UC-2Y8dQb0S6DtpxNgAKoJKA
10:20:45 PM Info Video Title: Date Z - Announce Trailer | PS5 & PS4 Games
10:20:45 PM Info Channel Id: UCelXvXZDvx8_TdOOffevzGg
10:20:45 PM Info Video Title: Space library tour with astronomer Jonathan McDowell!
10:20:45 PM Info Channel Id: UCUOilIEi4sJqM8Z1W53RXZw
10:20:45 PM Info Video Title: Dread the Dragons! | The Vallorian Legend | Chapter 21 | Elvenar
10:20:45 PM Info Channel Id: UCiHVGt9LmI1SBaswRg3Ufnw
10:20:45 PM Info Video Title: EVİNİZDE 3 PATATES VE 1 YUMURTANIZ VARSA‼️ BU KOLAY VE LEZZETLİ PATATES TARİFİNİ HAZIRLAYIN🤌
10:20:45 PM Info Channel Id: UCRSx63y-VPidCrycgDS-o_Q
10:20:45 PM Info Video Title: [SOLVED] Bone Heat Weighting failed (Automatic Weights doesn't work in Blender)
10:20:43 PM Notice Execution completed