<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>The Ops Community ⚙️: Jhon Mu</title>
    <description>The latest articles on The Ops Community ⚙️ by Jhon Mu (@jhonmu7383).</description>
    <link>https://community.ops.io/jhonmu7383</link>
    <image>
      <url>https://community.ops.io/images/E952Xgn4bxtAao952aEf-CHcgmhjEPO8c_neqLtidOc/rs:fill:90:90/g:sm/mb:500000/ar:1/aHR0cHM6Ly9jb21t/dW5pdHkub3BzLmlv/L3JlbW90ZWltYWdl/cy91cGxvYWRzL3Vz/ZXIvcHJvZmlsZV9p/bWFnZS8yNDE0MS8z/ZDYxMWM3ZC05NDE0/LTQ2ZjYtOTlhZC03/MjdmMDJiN2VkN2Eu/anBlZw</url>
      <title>The Ops Community ⚙️: Jhon Mu</title>
      <link>https://community.ops.io/jhonmu7383</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://community.ops.io/feed/jhonmu7383"/>
    <language>en</language>
    <item>
      <title>Auto-Save Your Discover Weekly with Spotify Bot</title>
      <dc:creator>Jhon Mu</dc:creator>
      <pubDate>Sun, 12 Oct 2025 06:38:07 +0000</pubDate>
      <link>https://community.ops.io/jhonmu7383/auto-save-your-discover-weekly-with-spotify-bot-3589</link>
      <guid>https://community.ops.io/jhonmu7383/auto-save-your-discover-weekly-with-spotify-bot-3589</guid>
      <description>&lt;p&gt;If you’re like me, your Discover Weekly playlist is one of your favorite parts of Monday. That perfect blend of new music, artists you’ve never heard of, and the occasional gem you end up obsessing over for weeks.&lt;/p&gt;

&lt;p&gt;But here's the catch: it disappears every week. If you don’t save that one track you loved, it’s gone — lost to the Spotify void forever.&lt;/p&gt;

&lt;p&gt;That got me thinking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Why isn’t there an easy way to automatically save Discover Weekly before it refreshes?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I decided to build it myself. A small, lightweight Node.js bot that runs once a week, grabs my Discover Weekly, and saves it into a dated playlist for easy reference later.&lt;/p&gt;

&lt;p&gt;And you can build it too — in under 100 lines of JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You’ll Need
&lt;/h2&gt;

&lt;p&gt;To follow along, here’s what you’ll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Spotify Developer Account&lt;/li&gt;
&lt;li&gt;A Spotify App (to get your Client ID &amp;amp; Secret)&lt;/li&gt;
&lt;li&gt;Node.js installed on your machine&lt;/li&gt;
&lt;li&gt;A bit of familiarity with JavaScript and APIs&lt;/li&gt;
&lt;li&gt;A free Spotify account (although premium unlocks more features)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Set Up OAuth with Spotify
&lt;/h2&gt;

&lt;p&gt;First, create your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir discover-weekly-archiver
cd discover-weekly-archiver
npm init -y
npm install express axios dotenv querystring open
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a .env file with your credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SPOTIFY_CLIENT_ID=your_client_id
SPOTIFY_CLIENT_SECRET=your_client_secret
SPOTIFY_REDIRECT_URI=http://localhost:8888/callback

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create your server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// auth-server.js
require('dotenv').config();
const express = require('express');
const axios = require('axios');
const querystring = require('querystring');
const open = require('open');

const app = express();
const port = 8888;

const SCOPES = [
  'playlist-read-private',
  'playlist-modify-private',
  'playlist-modify-public',
  'user-read-email',
].join(' ');

app.get('/login', (req, res) =&amp;gt; {
  const params = querystring.stringify({
    response_type: 'code',
    client_id: process.env.SPOTIFY_CLIENT_ID,
    scope: SCOPES,
    redirect_uri: process.env.SPOTIFY_REDIRECT_URI,
  });

  res.redirect(`https://accounts.spotify.com/authorize?${params}`);
});

app.get('/callback', async (req, res) =&amp;gt; {
  const code = req.query.code;

  const tokenResponse = await axios.post(
    'https://accounts.spotify.com/api/token',
    querystring.stringify({
      grant_type: 'authorization_code',
      code,
      redirect_uri: process.env.SPOTIFY_REDIRECT_URI,
    }),
    {
      headers: {
        Authorization:
          'Basic ' +
          Buffer.from(
            `${process.env.SPOTIFY_CLIENT_ID}:${process.env.SPOTIFY_CLIENT_SECRET}`
          ).toString('base64'),
        'Content-Type': 'application/x-www-form-urlencoded',
      },
    }
  );

  const { access_token, refresh_token } = tokenResponse.data;

  console.log('Access Token:', access_token);
  console.log('Refresh Token:', refresh_token);
  res.send('✅ Authenticated! You can now run your script.');
});

app.listen(port, () =&amp;gt; {
  console.log(`Visit http://localhost:${port}/login to authenticate`);
  open(`http://localhost:${port}/login`);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node auth-server.js

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step gives you an access token and refresh token — copy and store them securely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Find Your Discover Weekly Playlist
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://spotipremiiumapk.com/" rel="noopener noreferrer"&gt;APK Spotify Premium&lt;/a&gt; assigns Discover Weekly the same ID for everyone, but it’s in a user-specific context. The easiest way to find it is to fetch your playlists and search by name.&lt;/p&gt;

&lt;p&gt;Here’s how:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function getDiscoverWeeklyPlaylist(token) {
  const res = await axios.get('https://api.spotify.com/v1/me/playlists?limit=50', {
    headers: { Authorization: `Bearer ${token}` },
  });

  const playlists = res.data.items;
  const discover = playlists.find(p =&amp;gt; p.name === 'Discover Weekly');

  return discover;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have the playlist object, grab its id and fetch the tracks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function getPlaylistTracks(token, playlistId) {
  const res = await axios.get(
    `https://api.spotify.com/v1/playlists/${playlistId}/tracks`,
    {
      headers: { Authorization: `Bearer ${token}` },
    }
  );

  return res.data.items.map(item =&amp;gt; item.track.uri);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Create a New Archive Playlist
&lt;/h2&gt;

&lt;p&gt;Now we’ll create a new playlist each week with the current date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function createArchivePlaylist(token, userId) {
  const today = new Date().toISOString().split('T')[0];

  const res = await axios.post(
    `https://api.spotify.com/v1/users/${userId}/playlists`,
    {
      name: `📦 Discover Weekly – ${today}`,
      description: 'Auto-archived Discover Weekly tracks',
      public: false,
    },
    {
      headers: {
        Authorization: `Bearer ${token}`,
        'Content-Type': 'application/json',
      },
    }
  );

  return res.data.id;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Add Tracks to the Archive
&lt;/h2&gt;

&lt;p&gt;Once we have the new playlist and the track URIs, just add them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function addTracks(token, playlistId, uris) {
  await axios.post(
    `https://api.spotify.com/v1/playlists/${playlistId}/tracks`,
    { uris },
    {
      headers: {
        Authorization: `Bearer ${token}`,
        'Content-Type': 'application/json',
      },
    }
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Wrap It All Up
&lt;/h2&gt;

&lt;p&gt;Here’s the full flow in one function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function archiveDiscoverWeekly(token) {
  const me = await axios.get('https://api.spotify.com/v1/me', {
    headers: { Authorization: `Bearer ${token}` },
  });

  const userId = me.data.id;

  const discover = await getDiscoverWeeklyPlaylist(token);
  if (!discover) {
    console.error('Could not find Discover Weekly!');
    return;
  }

  const uris = await getPlaylistTracks(token, discover.id);

  const newPlaylistId = await createArchivePlaylist(token, userId);
  await addTracks(token, newPlaylistId, uris);

  console.log(`✅ Archived ${uris.length} tracks from Discover Weekly!`);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bonus: Automate with a Cron Job
&lt;/h2&gt;

&lt;p&gt;Want this to run automatically every week? Use a cron job or set up a task with node-cron.&lt;/p&gt;

&lt;p&gt;Install the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install node-cron
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this to your script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const cron = require('node-cron');

cron.schedule('0 9 * * MON', () =&amp;gt; {
  archiveDiscoverWeekly('your_access_token_here');
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it runs every Monday at 9am.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This might be a simple project, but it solves a real, everyday problem.&lt;/p&gt;

&lt;p&gt;I didn’t want to build something flashy or complex — just a practical utility that lets me hold on to the music I love before Spotify wipes it clean each week.&lt;/p&gt;

&lt;p&gt;It’s lightweight, fast, and it works.&lt;/p&gt;

&lt;p&gt;If you’re like me and Discover Weekly is a key part of your weekly music discovery, I highly recommend setting this up. You’ll thank yourself months from now when you rediscover that one song you forgot existed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to Take It Further?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Auto-post your weekly archive to Discord or Slack&lt;/li&gt;
&lt;li&gt;Store archived track data in a database for future analysis&lt;/li&gt;
&lt;li&gt;Build a web dashboard to browse your weekly archives&lt;/li&gt;
&lt;li&gt;Analyze track features over time to see how your taste evolves&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>secops</category>
      <category>aws</category>
      <category>cloudops</category>
    </item>
  </channel>
</rss>
