Skip to content

Instantly share code, notes, and snippets.

@hoony0203
Last active May 17, 2025 05:03
Show Gist options
  • Save hoony0203/2007684ccf30c2075c25d457014fad9f to your computer and use it in GitHub Desktop.
Save hoony0203/2007684ccf30c2075c25d457014fad9f to your computer and use it in GitHub Desktop.

This code refer hazycora's gist

and fixed(encode channel title issue) by Claude AI.


  • How to USE
  1. Go to youtube.com/feed/channels
  2. Paste below codes into Devtools and Enter.
  • If you got Devtools paste error message(warnings), just type WITH QUOTES 'allow pasting', or in korean '붙여넣기 허용'.

function getLast() {
  return ytInitialData.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents.slice(-1)[0];
}

function canContinue() { 
  return getLast().continuationItemRenderer != null;
}

(async () => {
  // Wait for all content to load
  while (canContinue()) {
    let current = getLast().continuationItemRenderer.continuationEndpoint.continuationCommand.token;
    scrollTo(0, document.getElementById('primary').scrollHeight);
    while (canContinue() && current == getLast().continuationItemRenderer.continuationEndpoint.continuationCommand.token) {
      await new Promise(r => setTimeout(r, 100));
    }
  }
  
  scrollTo(0, 0);
  
  // Create floating container
  const floatDiv = document.createElement('div');
  const preText = document.createElement('pre');
  floatDiv.setAttribute('style', `
    position: fixed;
    background: #0f0f0f;
    z-index: 100000;
    inset: 2rem;
    overflow: auto;
    font-size: 2rem;
    white-space: pre;
    color: white;
    padding: 1rem;
  `);

  // Process channel data with proper encoding
  const channels = ytInitialData.contents.twoColumnBrowseResultsRenderer.tabs[0]
    .tabRenderer.content.sectionListRenderer.contents
    .map(e => {
      if (!e.itemSectionRenderer) return null;
      return e.itemSectionRenderer.contents[0].shelfRenderer.content
        .expandedShelfContentsRenderer.items;
    })
    .flat()
    .filter(Boolean)
    .map(e => {
      if (!e.channelRenderer) return null;
      return {
        id: e.channelRenderer.channelId,
        url: `http://www.youtube.com/channel/${e.channelRenderer.channelId}`,
        title: e.channelRenderer.title.simpleText
      };
    })
    .filter(Boolean);

  // Create CSV with BOM for Unicode support
  const BOM = '\uFEFF';
  const headers = ['Channel Id', 'Channel Url', 'Channel Title'];
  const csvRows = [
    headers.join(','),
    ...channels.map(channel => 
      [
        channel.id,
        channel.url,
        // Properly escape title to handle commas and quotes
        `"${channel.title.replace(/"/g, '""')}"`
      ].join(',')
    )
  ];
  
  const csvContent = BOM + csvRows.join('\n');
  preText.textContent = csvContent;

  // Create download button
  const downloadLink = document.createElement('a');
  downloadLink.innerText = 'Download CSV (Unicode)';
  downloadLink.setAttribute('target', '_blank');
  downloadLink.setAttribute('style', `
    color: #bf3838;
    font-weight: bold;
    margin-bottom: 1rem;
    display: block;
    padding: 1rem;
    border-radius: 0.5rem;
    border: 2px solid #bf3838;
    width: fit-content;
    text-decoration: none;
  `);

  // Create blob with proper encoding
  const blob = new Blob([csvContent], { 
    type: 'text/csv;charset=utf-8'
  });
  downloadLink.href = URL.createObjectURL(blob);
  downloadLink.download = 'youtube_subscriptions.csv';

  // Append elements
  floatDiv.appendChild(downloadLink);
  floatDiv.appendChild(preText);
  document.body.appendChild(floatDiv);
})();
@dehardstyler
Copy link

It works, thanks a lot!

@feikescholtens
Copy link

Didn't work for me, only if updated getLast()

function getLast() { return ytInitialData.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content; }

Thanks for the effort though

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