Pages

Se afișează postările cu eticheta tutorial. Afișați toate postările
Se afișează postările cu eticheta tutorial. Afișați toate postările

joi, 20 noiembrie 2025

Google Apps Script : keep sheets whose names include today’s date ...

Today, this simple example will keep sheets whose names include today’s date in flexible regex formats
The script not include the month names (e.g., “20-Nov-2025”)
On running keeps sheets whose names contain any of these combinations; deletes the rest.
Let's see the source code:
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");
}

miercuri, 12 noiembrie 2025

Google Apps Script : how to filter data by the value in a cell and reset the filter.

If you look at this blog, you will find examples of the results of running GAScript scripts in Excel. Today, I will show you how to filter the entire table based on a value from a cell and how to reset it to the original result without filtering.
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}`);
}

vineri, 29 august 2025

PyQt6 : ... management of installations and build python package.

Yesterday I created a small project for managing Python packages and building a new package based on added modules. I only tested the local installations of various Python versions and the creation of a new package, but it worked.
python catafest_build_package_001.py
🔍 Verificare module standard...
[✓] Modul standard 'json' este disponibil.
[✓] Modul standard 'subprocess' este disponibil.
[✓] Modul standard 'platform' este disponibil.
[✓] Modul standard 'datetime' este disponibil.
[✓] Modul standard 'os' este disponibil.
[✓] Modul standard 'sys' este disponibil.

📦 Verificare și instalare module pip...
[✓] Modulul 'PyQt6' este deja instalat.
[✓] Modulul 'build' este deja instalat.
* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
  - setuptools
  - wheel
...

sâmbătă, 28 iunie 2025

Blender 3D : create winter sprites with RealSnow addon.

A simple method to create snow sprites. I imported an image with a fence, created a roof for each slat using a subdivided and bent plane to be able to put snow with the RealSnow addon. I used an array to create a matrix and used the RealSnow addon to add the snow. I just need to hide the fence, and as it looks from the render, I will have various sprites for the fence.

vineri, 27 iunie 2025

News : Discord limited channels and whiteboard app.

I tried few days ago to use an discord server invitation, but I got an error ... this is the main reason:
Your invite issue and the notification about reaching the channel limit relate to Discord's restrictions on server and channel memberships. Users can only join up to 100 servers (or up to 200 with Discord Nitro) and per server, the maximum channel limit is 500.
Discord comes with an whiteboard application for teams and users:

joi, 19 iunie 2025

News : Google Apps Script - get products by region into new sheet.

... this is source code for search products on my region using google apps script:
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);
  }
}

joi, 24 aprilie 2025

News : This FREE Add-on FIXES Blender’s Biggest Annoyance!

joi, 17 aprilie 2025

Artificial Intelligence: Ollama duplicate model .

Ollama can be install on your computer and changed according with your hardware requirements.
I will show how to duplicate a model and use it, see these commands:
D:\AI_Ollama>ollama list
NAME                ID              SIZE      MODIFIED
orca-mini:3b        2dbd9f439647    2.0 GB    16 hours ago
tinyllama:latest    2644915ede35    637 MB    16 hours ago
gemma2:2b           8ccf136fdd52    1.6 GB    16 hours ago
llama3.1:latest     46e0c10c039e    4.9 GB    5 weeks ago
llava:latest        8dd30f6b0cb1    4.7 GB    2 months ago

D:\AI_Ollama>
D:\AI_Ollama>
D:\AI_Ollama>
D:\AI_Ollama>ollama show tinyllama:latest --modelfile
# Modelfile generated by "ollama show"
# To build a new Modelfile based on this, replace FROM with:
# FROM tinyllama:latest

FROM C:\Users\nicol\.ollama\models\blobs\sha256-2af...
TEMPLATE "<|system|>
{{ .System }}
<|user|>
{{ .Prompt }}
<|assistant|>
"
SYSTEM You are a helpful AI assistant.
PARAMETER stop <|system|>
PARAMETER stop <|user|>
PARAMETER stop <|assistant|>
PARAMETER stop 


D:\AI_Ollama>ollama show tinyllama:latest --modelfile >  new.modelfile

gathering model components
gathering model components
gathering model components
gathering model components
gathering model components
gathering model components
gathering model components
gathering model components
copying file sha256:2af3b81862c6be03c769683af18efdadb2c33f60ff32ab6f83e42c043d6c7816 100%
parsing GGUF
using existing layer sha256:2af3b81862c6be03c769683af18efdadb2c33f60ff32ab6f83e42c043d6c7816
using existing layer sha256:af0ddbdaaa26f30d54d727f9dd944b76bdb926fdaf9a58f63f78c532f57c191f
using existing layer sha256:c8472cd9daed5e7c20aa53689e441e10620a002aacd58686aeac2cb188addb5c
using existing layer sha256:fa956ab37b8c21152f975a7fcdd095c4fee8754674b21d9b44d710435697a00d
writing manifest
success

D:\AI_Ollama>ollama list
NAME                    ID              SIZE      MODIFIED
new-tinyllama:latest    add64faa5d3b    637 MB    5 seconds ago
orca-mini:3b            2dbd9f439647    2.0 GB    16 hours ago
tinyllama:latest        2644915ede35    637 MB    16 hours ago
gemma2:2b               8ccf136fdd52    1.6 GB    16 hours ago
llama3.1:latest         46e0c10c039e    4.9 GB    5 weeks ago
llava:latest            8dd30f6b0cb1    4.7 GB    2 months ago

D:\AI_Ollama>ollama run new-tinyllama:latest
>>> Hello
Yes, of course! I'm happy to hear that you found my message helpful. Let
me know if you have any further questions or concerns in the future. If
you need further assistance, feel free to reach out again at your
convenience. Have a great day!

>>> Send a message (/? for help)

miercuri, 16 aprilie 2025

News : Google Apps Script - add movies from website into new sheet.

This source code with GAScript add few movies from cinemagia website:
The commant the lines from the last post tutorial and use this source code.
This will add movies into separated sheet by date, see the source code:
  // try {
  //   const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  //   const currentDate = new Date();
  //   extractedData.forEach((movie, rowIndex) =&gt; {
  //     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) =&gt; {
    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);
}

News : Viewing HTML in your Terminal by Kris Occhipinti.

This is an old channel with good content that I was looking at about 10 years ago... My internet content is being cut for some reason and I saw this new video today.

sâmbătă, 29 martie 2025

News : Google Apps Script - add movies from website.

This source code with GAScript add few movies from cinemagia website:
This is the source code:
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(/&lt;li class="first"&gt;(.*?)&lt;\/li&gt;/g)];
  const images = [...text.matchAll(/&lt;img src="(https:\/\/static\.cinemagia\.ro\/img\/resize\/db\/movie.*?)"/g)];
  const channels = [...text.matchAll(/&lt;span class="r1"&gt;(.*?)&lt;\/span&gt;/g)];
  const times = [...text.matchAll(/&lt;span class="r2"&gt;(.*?)&lt;\/span&gt;/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) =&gt; {
    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) =&gt; {
      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);
  }
}

marți, 25 martie 2025

News : Google Apps Script - find duplicate files in google drive.

For today, a simple GAScript source code to add into spreadsheet the duplicate files from Google drive.
This Google Apps Script finds duplicate files in Google Drive by comparing file sizes and optionally file types. It then displays the results in a spreadsheet with detailed information about each duplicate file. The script collects information about all files in Drive. Files are grouped by their size and optionally file type. Any group with more than one file is considered a set of duplicates These duplicate sets are displayed in the spreadsheet
Functions
  • checkDuplicatesInDrive(): Main function that searches your entire Google Drive for duplicates
  • checkDuplicatesInFolder(): Alternative function that searches a specific folder and its subfolders
  • findDuplicateFiles(): Core function that identifies duplicate files based on size and type
  • addDuplicatesToSheet(): Adds the found duplicates to a spreadsheet
I used artificial inteligence and this help me much ...
/**
 * 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();
}
See the result into the spreadsheet:

luni, 17 martie 2025

News : New changes in pluralsight website.

I leran from this website and I tested my skills and is a great tool with certification and training.
Is a little bit expensive for me because I learn a lot of programming, design, game engines and API.
If I had gotten certificates for everything, for how much the exams cost, I would have to be very rich.
The only way to make a correct statement without enormous cost is online tests and the results obtained and the webiste comes with tested area.
The area of learning is:
  • IT Ops
  • Cloud
  • Security
  • Project Management
  • Data
  • Software Development
  • Popular Certifications
  • Newest
The newest now has Iris witch is a: Jumpstart a new conversation with one of our quick prompts.
See some my tested and learning skills on this website:

marți, 4 februarie 2025

Blender 3D : fix deformation Array of Curve modifier.

Possible bug ...
I noticed after creating an Array with an object and a NurbsPath object in Blender 3D version 4.3.2 and after the classic basic operations aligned, scaled and applied all transformations of these two objects, distortions appear when applying the Curve modifier to the Array object. I do not know the cause; it is possible a bug. It can be solved if you convert the NurbsPath to a new type of Curve object from the main menu Object - Convert - Curve, then applying the Deform Curve modifier will not deform the Array object.

sâmbătă, 11 ianuarie 2025

Blender 3D : How to Extract Marvel Rivals 3D Model and Use in Blender.

For those who are Marvel Rivals fans or study gaming files, here is a useful video tutorial.

joi, 2 ianuarie 2025

News : Roblox Studio changes and access places

Roblox comes with new features into Roblox Editor.
One is the the palaces area witch is Private - security reason by team developmen, and you not see this type of scene into default Roblox Studio Editor.
If you want to edit one of this you need to use this way, see this screenshot from the official webpage.

duminică, 29 decembrie 2024

Blender 3D : ... all available nodes !

An old surce code in python for Blender 3D to see available nodes :
import bpy

node_tree = bpy.context.object.active_material.node_tree

location_x = 0
location_y = 0

for type in dir(bpy.types):
    real_type = getattr(bpy.types, type)
    if issubclass(real_type, bpy.types.ShaderNode):
        try:
            node = node_tree.nodes.new(type)
            node.width = 250
            node.location = (location_x, location_y)
            location_x += 300
            if location_x > 3000:
                location_x = 0
                location_y -= 600
        except:
            pass

duminică, 1 decembrie 2024

Inkscape : watercolor effect on inkscape version 1.4 .

... the watercolor effect in inkscape can be found in the main menu : Filters - Textures - Watercolor.
Just draw a shape an then select the filter.
Use Filters - Filter Editor ... to edit the filter, see this image: