File size: 5,429 Bytes
96d6e99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// SCRAPE BY NEKOLABS
// CHANNEL WA: https://whatsapp.com/channel/0029VbANq6v0VycMue9vPs3u

const axios = require("axios");
const cheerio = require("cheerio");

class NCS {
  constructor() {
    this.baseUrl = "https://ncs.io";

    this.validGenres = {
      "31": "Alternative Dance", "33": "Alternative Pop", "23": "Ambient", "34": "Anti-Pop",
      "1": "Bass", "18": "Bass House", "26": "Brazilian Phonk", "27": "Breakbeat",
      "2": "Chill", "24": "Chill Bass", "35": "Chill Pop", "85": "Colour Bass",
      "65": "Complextro", "36": "Dance-Pop", "66": "Deep House", "45": "Disco",
      "46": "Disco House", "3": "Drum & Bass", "4": "Drumstep", "5": "Dubstep",
      "6": "EDM", "47": "Electro", "48": "Electro House", "7": "Electronic",
      "39": "Electronic Pop", "83": "Electronic Rock", "17": "Future Bass", "68": "Future Bounce",
      "8": "Future House", "69": "Future Rave", "57": "Future Trap", "40": "Futurepop",
      "51": "Garage", "15": "Glitch Hop", "82": "Hardcore", "9": "Hardstyle",
      "10": "House", "41": "Hyperpop", "11": "Indie Dance", "91": "J-Pop",
      "84": "Jersey Club", "28": "Jump-Up", "29": "Liquid DnB", "60": "Lofi Hip-Hop",
      "12": "Melodic Dubstep", "54": "Melodic House", "22": "Midtempo Bass", "30": "Neurofunk",
      "87": "Nu-Jazz", "16": "Phonk", "86": "Pluggnb", "19": "Pop",
      "55": "Progressive House", "88": "RnB", "89": "Speed Garage", "73": "Tech House",
      "80": "Techno", "81": "Trance", "14": "Trap", "74": "Tribal House",
      "21": "UKG", "90": "Witch House"
    };

    this.validMoods = {
      "1": "Angry", "33": "angry", "26": "Chasing", "2": "Dark", "35": "dark",
      "36": "dramatic", "3": "Dreamy", "27": "Eccentric", "28": "Elegant", "6": "energetic",
      "4": "Epic", "5": "Euphoric", "37": "exciting", "7": "Fear", "29": "Floating",
      "8": "Funny", "9": "Glamorous", "10": "Gloomy", "11": "Happy", "30": "Heavy",
      "12": "Hopeful", "13": "Laid Back", "38": "majestic", "14": "Mysterious", "34": "negative",
      "39": "neutral", "15": "Peaceful", "40": "positive", "32": "powerful", "16": "Quirky",
      "17": "relaxed", "18": "Restless", "19": "romantic", "20": "sad", "21": "scary",
      "31": "Sentimental", "22": "Sexy", "23": "Suspense", "41": "tense", "24": "Weird"
    };
  }

  validateParam(type, value) {
    const validList = type === "genre" ? this.validGenres : this.validMoods;
    return value && validList[value] ? String(value) : "";
  }

  async searchTracks(query, genre = "", mood = "") {
    try {
      const validGenre = this.validateParam("genre", genre);
      const validMood = this.validateParam("mood", mood);
      const url = `${this.baseUrl}/music-search?q=${encodeURIComponent(query)}&genre=${validGenre}&mood=${validMood}`;

      const { data } = await axios.get(url, {
        headers: {
          "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
        }
      });

      const $ = cheerio.load(data);
      const tracks = [];

      $("table.tablesorter tbody tr").each((_, el) => {
        const $row = $(el);
        const $play = $row.find(".player-play");

        const tid = $play.attr("data-tid") || "";
        const title = $play.attr("data-track") || "";
        const artist = $play.attr("data-artistraw") || "";
        const versions = $play.attr("data-versions") || "";
        const genre = $play.attr("data-genre") || "";
        const previewUrl = $play.attr("data-url") || "";
        const previewStart = $play.attr("data-preview") || "0";
        const image = $row.find("td img[alt]").attr("src") || "";

        const genres = [];
        const moods = [];

        $row.find("td:nth-child(5) a.tag").each((i, tag) => {
          const $tag = $(tag);
          const text = $tag.text().trim();
          const href = $tag.attr("href") || "";
          if (href.includes("genre=")) genres.push(text);
          else if (href.includes("mood=")) moods.push(text);
        });

        const releaseDate = $row.find("td:nth-child(6)").text().trim();

        if (tid && title) {
          tracks.push({
            tid,
            title,
            artist,
            versions,
            genre,
            image,
            genres,
            moods,
            previewUrl,
            previewStart,
            releaseDate
          });
        }
      });

      return tracks;
    } catch (err) {
      console.error("Error while searching NCS:", err.message);
      return [];
    }
  }
}

const ncs = new NCS();

const handler = async (req, res) => {
  try {
    const { text, genre, mood } = req.query;

    if (!text) {
      return res.status(400).json({
        success: false,
        error: 'Missing required parameter: text'
      });
    }

    const results = await ncs.searchTracks(text, genre || "", mood || "");

    res.json({
      author: 'Herza',
      success: true,
      data: results
    });

  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
};

module.exports = {
  name: 'NCS Music Search',
  description: 'Search NoCopyrightSounds tracks by keyword with optional genre and mood filters',
  type: 'GET',
  routes: ['api/search/ncs'],
  tags: ['search', 'music', 'ncs', 'tools'],
  parameters: ['text', 'genre (optional)', 'mood (optional)'],
  enabled: true,
  main: ['Search'],
  handler
};