Skip to content

Create unavatools.js#2425

Closed
OrangeHub10 wants to merge 2 commits into
TurboWarp:masterfrom
OrangeHub10:patch-1
Closed

Create unavatools.js#2425
OrangeHub10 wants to merge 2 commits into
TurboWarp:masterfrom
OrangeHub10:patch-1

Conversation

@OrangeHub10

Copy link
Copy Markdown

This extension integrates the Unavatar.io API to fetch profile pictures and provides blocks to open social media profiles directly from TurboWarp

This extension integrates the Unavatar.io API to fetch profile pictures and provides blocks to open social media profiles directly from TurboWarp
@github-actions github-actions Bot added the pr: new extension Pull requests that add a new extension label Mar 1, 2026
@OrangeHub10

Copy link
Copy Markdown
Author

Xtras: also, this is made by google AI and me(i also needed to fix code from AI, Also i tried to create code by myself), and THIS MUST RUN UNDSANDBOXED, because of 2 command blocks

@Brackets-Coder

Copy link
Copy Markdown
Contributor

Xtras: also, this is made by google AI and me(i also needed to fix code from AI, Also i tried to create code by myself), and THIS MUST RUN UNDSANDBOXED, because of 2 command blocks

any extension being added to the gallery runs unsandboxed.

@OrangeHub10

Copy link
Copy Markdown
Author

@Brackets-Coder YEP!, because of the command blocks, it MUST RUN UNDSANDBOXED, because both uses windows.open

@OrangeHub10

Copy link
Copy Markdown
Author

also this is the code backup!:(function(Scratch) {
'use strict';

class Unavatar {
getInfo() {
return {
id: 'unavatartools',
name: 'Unavatar Tools',
color1: '#4a4a4a',
color2: '#333333',
blocks: [
{
opcode: 'getProfilePic',
blockType: Scratch.BlockType.REPORTER,
text: 'get pfp unavatar user image with provider [PROVIDER] size [SIZE] user [USERNAME] fallback [FALLBACK]',
arguments: {
PROVIDER: { type: Scratch.ArgumentType.STRING, menu: 'providersMenu', defaultValue: 'github' },
USERNAME: { type: Scratch.ArgumentType.STRING, defaultValue: 'kikobeats' },
SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 400 },
FALLBACK: { type: Scratch.ArgumentType.STRING, defaultValue: '' }
}
},
{
opcode: 'getAvatarByEmail',
blockType: Scratch.BlockType.REPORTER,
text: 'unavatar of email [EMAIL] size [SIZE]',
arguments: {
EMAIL: { type: Scratch.ArgumentType.STRING, defaultValue: 'hello@microlink.io' },
SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 400 }
}
},
{
opcode: 'getDomainLogo',
blockType: Scratch.BlockType.REPORTER,
text: 'logo of website [DOMAIN] via Google size [SIZE]',
arguments: {
DOMAIN: { type: Scratch.ArgumentType.STRING, defaultValue: 'turbowarp.org' },
SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 400 }
}
},
{
opcode: 'GetDomainLogoNoGoogle',
blockType: Scratch.BlockType.REPORTER,
text: 'Get domain logo [DOMAINLOGO] size [SIZEDOMAINLOGO]',
arguments: {
DOMAINLOGO: { type: Scratch.ArgumentType.STRING, defaultValue: 'hello@microlink.io' },
SIZEDOMAINLOGO: { type: Scratch.ArgumentType.NUMBER, defaultValue: 400 }
}
},
{
opcode: 'openProfile',
blockType: Scratch.BlockType.COMMAND,
text: 'Open profile of [PROVIDER] user [USERNAME]',
arguments: {
PROVIDER: { type: Scratch.ArgumentType.STRING, menu: 'allProvidersMenu', defaultValue: 'github' },
USERNAME: { type: Scratch.ArgumentType.STRING, defaultValue: 'kikobeats' }
}
},
{
opcode: 'GetProfilePicSize',
blockType: Scratch.BlockType.COMMAND,
text: 'Open unavatar image in new tab [PROVIDERSIZE] user [USERSIZE] size [SIZE]',
arguments: {
PROVIDERSIZE: { type: Scratch.ArgumentType.STRING, menu: 'providersMenu', defaultValue: 'github' },
USERSIZE: { type: Scratch.ArgumentType.STRING, defaultValue: 'kikobeats' },
SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 400 }
}
}
],
menus: {
providersMenu: {
acceptReporters: true,
items: [
'github', 'twitter', 'instagram', 'youtube', 'facebook',
'reddit', 'tiktok', 'twitch', 'soundcloud', 'telegram',
'duckduckgo', 'deviantart', 'dribbble', 'bluesky', 'mastodon', 'threads'
]
},
allProvidersMenu: {
acceptReporters: true,
items: [
'github', 'twitter', 'instagram', 'youtube', 'facebook',
'reddit', 'tiktok', 'twitch', 'soundcloud', 'telegram',
'apple-music', 'spotify', 'patreon'
]
}
}
};
}

_buildUrl(path, size, fallback) {
  const s = size || 400;
  let url = `https://unavatar.io/${path}?size=${s}`;
  if (fallback) {
    url += `&fallback=${encodeURIComponent(fallback)}`;
  }
  return url;
}

getProfilePic(args) {
  const provider = String(args.PROVIDER).toLowerCase().trim();
  const user = encodeURIComponent(args.USERNAME);
  return this._buildUrl(`${provider}/${user}`, args.SIZE, args.FALLBACK);
}

getAvatarByEmail(args) {
  const email = encodeURIComponent(args.EMAIL);
  return this._buildUrl(email, args.SIZE);
}

getDomainLogo(args) {
  const domain = encodeURIComponent(args.DOMAIN);
  return this._buildUrl(`google/${domain}`, args.SIZE);
}

GetDomainLogoNoGoogle(args) {
  const domain = encodeURIComponent(args.DOMAINLOGO);
  return this._buildUrl(domain, args.SIZEDOMAINLOGO);
}

openProfile(args) {
  const provider = String(args.PROVIDER).toLowerCase().trim();
  const userEnc = encodeURIComponent(args.USERNAME);
  
  const profiles = {
    'github': `https://github.com/${userEnc}`,
    'twitter': `https://twitter.com/${userEnc}`,
    'instagram': `https://instagram.com{/$ userEnc}`,
    'youtube': `https://youtube.com/${userEnc}`, 
    'twitch': `https://twitch.tv/${userEnc}`,
    'apple-music': `https://music.apple.com/${userEnc}`,
    'spotify': `https://open.spotify.com/${userEnc}`,
    'patreon': `https://www.patreon.com/${userEnc}`
  };

  const url = profiles[provider] || `https://unavatar.io{provider}/${userEnc}`;
  if (typeof window !== 'undefined') window.open(url, '_blank', 'noopener,noreferrer');
}

GetProfilePicSize(args) {
  const url = this.getProfilePic({
    PROVIDER: args.PROVIDERSIZE,
    USERNAME: args.USERSIZE,
    SIZE: args.SIZE,
    FALLBACK: ''
  });
  if (typeof window !== 'undefined') window.open(url, '_blank', 'noopener,noreferrer');
}

}

Scratch.extensions.register(new Unavatar());
})(Scratch);

@that-random-programmer

Copy link
Copy Markdown

also this is the code backup!:(function(Scratch) {

'use strict';

class Unavatar {

getInfo() {

  return {

    id: 'unavatartools',

    name: 'Unavatar Tools',

    color1: '#4a4a4a',

    color2: '#333333',

    blocks: [

      {

        opcode: 'getProfilePic',

        blockType: Scratch.BlockType.REPORTER,

        text: 'get pfp unavatar user image with provider [PROVIDER] size [SIZE] user [USERNAME] fallback [FALLBACK]', 

        arguments: {

          PROVIDER: { type: Scratch.ArgumentType.STRING, menu: 'providersMenu', defaultValue: 'github' },

          USERNAME: { type: Scratch.ArgumentType.STRING, defaultValue: 'kikobeats' },

          SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 400 },

          FALLBACK: { type: Scratch.ArgumentType.STRING, defaultValue: '' }

        }

      },

      {

        opcode: 'getAvatarByEmail',

        blockType: Scratch.BlockType.REPORTER,

        text: 'unavatar of email [EMAIL] size [SIZE]',

        arguments: {

          EMAIL: { type: Scratch.ArgumentType.STRING, defaultValue: 'hello@microlink.io' },

          SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 400 }

        }

      },

      {

        opcode: 'getDomainLogo',

        blockType: Scratch.BlockType.REPORTER,

        text: 'logo of website [DOMAIN] via Google size [SIZE]',

        arguments: {

          DOMAIN: { type: Scratch.ArgumentType.STRING, defaultValue: 'turbowarp.org' },

          SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 400 }

        }

      },

      {

        opcode: 'GetDomainLogoNoGoogle',

        blockType: Scratch.BlockType.REPORTER,

        text: 'Get domain logo [DOMAINLOGO] size [SIZEDOMAINLOGO]',

        arguments: {

          DOMAINLOGO: { type: Scratch.ArgumentType.STRING, defaultValue: 'hello@microlink.io' },

          SIZEDOMAINLOGO: { type: Scratch.ArgumentType.NUMBER, defaultValue: 400 }

        }

      },

      {

        opcode: 'openProfile',

        blockType: Scratch.BlockType.COMMAND,

        text: 'Open profile of [PROVIDER] user [USERNAME]',

        arguments: {

          PROVIDER: { type: Scratch.ArgumentType.STRING, menu: 'allProvidersMenu', defaultValue: 'github' },

          USERNAME: { type: Scratch.ArgumentType.STRING, defaultValue: 'kikobeats' }

        }

      },

      {

        opcode: 'GetProfilePicSize',

        blockType: Scratch.BlockType.COMMAND,

        text: 'Open unavatar image in new tab [PROVIDERSIZE] user [USERSIZE] size [SIZE]',

        arguments: {

          PROVIDERSIZE: { type: Scratch.ArgumentType.STRING, menu: 'providersMenu', defaultValue: 'github' },

          USERSIZE: { type: Scratch.ArgumentType.STRING, defaultValue: 'kikobeats' },

          SIZE: { type: Scratch.ArgumentType.NUMBER, defaultValue: 400 }

        }

      }

    ],

    menus: {

      providersMenu: {

        acceptReporters: true,

        items: [

          'github', 'twitter', 'instagram', 'youtube', 'facebook',

          'reddit', 'tiktok', 'twitch', 'soundcloud', 'telegram',

          'duckduckgo', 'deviantart', 'dribbble', 'bluesky', 'mastodon', 'threads'

        ]

      },

      allProvidersMenu: {

        acceptReporters: true,

        items: [

          'github', 'twitter', 'instagram', 'youtube', 'facebook',

          'reddit', 'tiktok', 'twitch', 'soundcloud', 'telegram',

          'apple-music', 'spotify', 'patreon'

        ]

      }

    }

  };

}



_buildUrl(path, size, fallback) {

  const s = size || 400;

  let url = `https://unavatar.io/${path}?size=${s}`;

  if (fallback) {

    url += `&fallback=${encodeURIComponent(fallback)}`;

  }

  return url;

}



getProfilePic(args) {

  const provider = String(args.PROVIDER).toLowerCase().trim();

  const user = encodeURIComponent(args.USERNAME);

  return this._buildUrl(`${provider}/${user}`, args.SIZE, args.FALLBACK);

}



getAvatarByEmail(args) {

  const email = encodeURIComponent(args.EMAIL);

  return this._buildUrl(email, args.SIZE);

}



getDomainLogo(args) {

  const domain = encodeURIComponent(args.DOMAIN);

  return this._buildUrl(`google/${domain}`, args.SIZE);

}



GetDomainLogoNoGoogle(args) {

  const domain = encodeURIComponent(args.DOMAINLOGO);

  return this._buildUrl(domain, args.SIZEDOMAINLOGO);

}



openProfile(args) {

  const provider = String(args.PROVIDER).toLowerCase().trim();

  const userEnc = encodeURIComponent(args.USERNAME);

  

  const profiles = {

    'github': `https://github.com/${userEnc}`,

    'twitter': `https://twitter.com/${userEnc}`,

    'instagram': `https://instagram.com{/$ userEnc}`,

    'youtube': `https://youtube.com/${userEnc}`, 

    'twitch': `https://twitch.tv/${userEnc}`,

    'apple-music': `https://music.apple.com/${userEnc}`,

    'spotify': `https://open.spotify.com/${userEnc}`,

    'patreon': `https://www.patreon.com/${userEnc}`

  };



  const url = profiles[provider] || `https://unavatar.io{provider}/${userEnc}`;

  if (typeof window !== 'undefined') window.open(url, '_blank', 'noopener,noreferrer');

}



GetProfilePicSize(args) {

  const url = this.getProfilePic({

    PROVIDER: args.PROVIDERSIZE,

    USERNAME: args.USERSIZE,

    SIZE: args.SIZE,

    FALLBACK: ''

  });

  if (typeof window !== 'undefined') window.open(url, '_blank', 'noopener,noreferrer');

}

}

Scratch.extensions.register(new Unavatar());

})(Scratch);

Mate, just saying, you don't have to add code backups to PR comment sections. GitHub is reliable enough, and event then, the chances of your code becoming corrupted are extremely tiny.

Just a small heads up

@OrangeHub10

Copy link
Copy Markdown
Author

@DELOLCAT Ok(i'm just preventing the extension to get corrupted but ok)

Comment thread extensions/unavatools.js
Comment on lines +1 to +5
// Name: Unavatar tools
// Id: unavatartools
// What it does: it gets unavatar images easily instead of external websites
// includes: 6 blocks, runs unsandboxed because of 2 blocks, doesn't use math, only
// strings, 4 reporters, 2 commands, what it can do, gets url images, opens tabs

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a small tip, you may want to replace this header with something like:

// Name: Unavatar Tools
// ID: unavatartools
// Description: Get Unavatar images easily instead of external websites.
// By: OrangeHub10 <https://scratch.mit.edu/users/IF-YOU-HAVE-A-SCRATCH-ACCOUNT-PUT-ITS-USERNAME-HERE/>
// Original: OnlyIfYourExtensionIsAForkOfAnother
// License: MPL-2.0

Your current header is very likely to fail CI.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would tend to agree

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That can be an alternative header(+ i have a scratch account)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That can be an alternative header(+ i have a scratch account)

That header is required to comply with the contributing guidelines.

@kanebuiltlegacy

Copy link
Copy Markdown

@OrangeHub10 i can get you a fast review if you want, I have GitHub Pro so I can request Copilot reviews. It'll give you insights on how to improve your code.

@OrangeHub10

Copy link
Copy Markdown
Author

@kx1xixit Thanks you! (i did not know about the existance of github pro)( also, my account is like any normal scratcher : https://scratch.mit.edu/users/orangescratcher9/ )

@kanebuiltlegacy

Copy link
Copy Markdown

@copilot review

@kanebuiltlegacy

Copy link
Copy Markdown

Dang, nevermind. I might need contributor permissions to assign Copilot as a reviewer, so nevermind lol

@OrangeHub10

Copy link
Copy Markdown
Author

@kx1xixit its ok, i think i dont need to change the code, its already enough with the code, let the code be like that(this is like the second extension i have made with ai and me) so yeah.

@kanebuiltlegacy

Copy link
Copy Markdown

@OrangeHub10 Your CI failed, just letting you know in case you forgot

@Brackets-Coder

Copy link
Copy Markdown
Contributor

!format

@Brackets-Coder

Copy link
Copy Markdown
Contributor

Depending on CORS proxy limitations, some of this extension's features are likely already available with a combination of other extensions such as fetch and Asset Manager

@kanebuiltlegacy

Copy link
Copy Markdown

@OrangeHub10 Just a quick heads-up, your CI failed a hot while ago. ESLint is mostly complaining about translation via Scratch.translate (the extension name and blocks), and using Scratch.openWindow instead of window.open.

@SharkPool-SP

Copy link
Copy Markdown
Collaborator

This PR should be closed. The functionality of this extension is easily recreateable with other existing extensions in the gallery (Fetch, Network, & Skins, are big examples). This is nothing more than basic url string concatenation and relying on a outside api for niche sites that contain avatars.

@OrangeHub10

Copy link
Copy Markdown
Author

@SharkPool-SP Yeah youre rigth, i need to cancel this, +, oficially , unavatar has now restricted rate limit use, so like its cancelledd. i will keep making other extensons, but this is cancelled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr: new extension Pull requests that add a new extension

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants