Browser‑Based Direct‑Link Downloader Clone

A minimal LinkSwift‑inspired downloader built with Node.js and SQLite

Welcome to another official UVF IT build guide! In the next 45 minutes you’ll create a tiny browser‑based direct‑link downloader that mimics the core of LinkSwift, using only free, open‑source tools.

We’ll scaffold a Node/Express app, store generated links in a local SQLite file, expose a tiny API, and serve a one‑page UI that lets you paste a URL and get a direct download link.

Before you start

Clone Architecture
LOCAL RUNTIME HTTP requests CRUD Browser UI HTML/JS Node.js Express Server API + UI SQLite DB links.db
1

Phase 1: Scaffold the project

Create a fresh folder for the clone, initialize a new npm project, and pull in the two dependencies we need – Express for the web server and better‑sqlite3 for a simple, synchronous SQLite wrapper. Doing it all in one line keeps the setup tidy and repeatable.

After this step you’ll have a package.json and a node_modules directory ready for the next phases.

mkdir linkswift-clone && cd linkswift-clone && npm init -y && npm install express better-sqlite3
2

Phase 2: Data model – SQLite helper

We create a tiny module (db.js) that opens (or creates) a links.db file in the project root. It ensures a links table exists and exports a saveLink(original, direct) function that inserts a row and returns its numeric id – the primary key we’ll later use to retrieve the link.

Using better‑sqlite3 means the API is synchronous, which keeps the code easy to read for beginners while still being performant for a small clone.

db.js

const Database = require('better-sqlite3');
const db = new Database('links.db');
// Ensure table exists
db.exec(`CREATE TABLE IF NOT EXISTS links (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  original TEXT NOT NULL,
  direct TEXT NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);`);
/**
 * Store a pair of URLs and get the row id.
 * @param {string} original - The URL the user pasted.
 * @param {string} direct   - The rewritten direct‑download URL.
 * @returns {number} The newly inserted row id.
 */
function saveLink(original, direct) {
  const stmt = db.prepare('INSERT INTO links (original, direct) VALUES (?, ?)');
  const info = stmt.run(original, direct);
  return info.lastInsertRowid;
}
module.exports = { saveLink };
3

Phase 3: API & UI – Express server

In this step we spin up an Express server that will act as the backend for our downloader clone. It will expose a /api/convert endpoint that accepts a JSON body with a url field, pretends to convert the link by appending ?download=1, stores the mapping in SQLite, and returns a short /d/:id link. We also add a redirect route /d/:id that looks up the stored direct link and sends the client there. Finally the server will serve static assets from the public folder so our UI can be loaded directly from the same origin.

server.js

const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const path = require('path');

const app = express();
const db = new sqlite3.Database('links.db');

// Initialise table if not present
db.run('CREATE TABLE IF NOT EXISTS links(id INTEGER PRIMARY KEY AUTOINCREMENT, original TEXT, direct TEXT)');

app.use(express.json());
app.use(express.static(path.join(__dirname, 'public')));

// API: receive a URL, fake‑convert it, store and return short link
app.post('/api/convert', (req, res) => {
  const {url} = req.body;
  if (!url) return res.status(400).json({error: 'url required'});
  const direct = url.includes('?') ? `${url}&download=1` : `${url}?download=1`;
  db.run('INSERT INTO links(original, direct) VALUES(?,?)', [url, direct], function(err){
    if (err) return res.status(500).json({error: err.message});
    const short = `/d/${this.lastID}`;
    res.json({short, direct});
  });
});

// Redirect short link to stored direct URL
app.get('/d/:id', (req, res) => {
  const id = req.params.id;
  db.get('SELECT direct FROM links WHERE id = ?', [id], (err, row) => {
    if (err || !row) return res.status(404).send('Not found');
    res.redirect(row.direct);
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`🚀 http://localhost:${PORT}`));
4

Phase 4: Minimal UI

Now we create a tiny HTML page that lets users paste any URL, hit a button, and see a short link generated by our API. The page lives in public/index.html and uses the Fetch API to POST the URL to /api/convert. When the response arrives we display the short link as a clickable anchor so the user can test the redirect immediately.

public/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>LinkSwift Clone</title>
  <style>
    body{font-family:sans-serif;margin:2rem}
    input,button{padding:.5rem;font-size:1rem}
    #result{margin-top:1rem}
  </style>
</head>
<body>
  <h1>Direct‑Link Downloader</h1>
  <input id="urlInput" type="text" placeholder="Enter a URL" size="50" />
  <button id="convertBtn">Get Short Link</button>
  <div id="result"></div>

  <script>
    document.getElementById('convertBtn').addEventListener('click', async () => {
      const url = document.getElementById('urlInput').value.trim();
      if (!url) return alert('Please enter a URL');
      const resp = await fetch('/api/convert', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({url})
      });
      const data = await resp.json();
      const link = document.createElement('a');
      link.href = data.short;
      link.textContent = `${window.location.origin}${data.short}`;
      const resultDiv = document.getElementById('result');
      resultDiv.innerHTML = '';
      resultDiv.appendChild(link);
    });
  </script>
</body>
</html>
5

Phase 5: Run & verify

With the server and UI in place, start the application and open the browser to see everything work together. Run node server.js to launch the Express app; you should see a console line with the local URL. Then navigate to that address, paste any HTTP URL into the input, click the button, and verify that the generated short link appears and redirects to the modified URL with ?download=1. This confirms the end‑to‑end flow of our minimal LinkSwift clone.

node server.js

Verifying the Stack

CheckCommand / Why it matters
Server starts without errorsnode server.js → should log ‘🚀 http://localhost:3000’"
UI loads in browserOpen http://localhost:3000 and see the input form"
Short link redirects correctlyEnter https://example.com, click button, then click generated link; you should be taken to https://example.com?download=1"

What’s next?

You now have a working clone. Extend it by adding real host‑specific parsers, shorten URLs with a hashids library, or deploy to a free cloud host like Railway.