const axios = require('axios'); class DevianArt { constructor() { this.inst = axios.create({ baseURL: 'https://www.deviantart.com', headers: { origin: 'https://www.deviantart.com', referer: 'https://www.deviantart.com/', 'user-agent': 'Mozilla/5.0 (Linux; Android 15; SM-F958 Build/AP3A.240905.015) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.86 Mobile Safari/537.36' } }); } getCsrf = async function () { try { const { data: html, headers } = await this.inst.get('/'); const csrf = html.match(/window\.__CSRF_TOKEN__\s*=\s*'([^']*)'/)?.[1]; if (!csrf) throw new Error('Failed to get csrf token.'); const cookies = headers['set-cookie']?.join('; ') || ''; this.inst.defaults.headers.common['cookie'] = cookies; return csrf; } catch (error) { throw new Error(error.message); } } search = async function ({ query, cursor } = {}) { try { if (!query) throw new Error('Query is required.'); const csrf = await this.getCsrf(); const { data } = await this.inst.get('/_puppy/dabrowse/search/all', { params: { q: query, da_minor_version: 20230710, csrf_token: csrf, ...(cursor && { cursor: cursor }) } }); return data; } catch (error) { throw new Error(error.message); } } detail = async function (url) { try { const match = url.match(/https?:\/\/(?:www\.)?deviantart\.com\/([^\/]+)\/(art|journal)\/[^\/]+-(\d+)/); if (!match) throw new Error('Invalid url.'); const csrf = await this.getCsrf(); const { data } = await this.inst.get('/_puppy/dadeviation/init', { params: { deviationid: match[3], username: match[1], type: match[2], include_session: false, csrf_token: csrf, expand: 'deviation.related', preload: true, da_minor_version: 20230710 } }); return data; } catch (error) { throw new Error(error.message); } } } // Usage: const d = new DevianArt(); d.search({ query: 'hutao' }).then(console.log);