Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The Google site has changed, breaking the converter #75

Open
AllyMcSqueal opened this issue Jan 22, 2025 · 10 comments
Open

The Google site has changed, breaking the converter #75

AllyMcSqueal opened this issue Jan 22, 2025 · 10 comments
Labels
help wanted Extra attention is needed

Comments

@AllyMcSqueal
Copy link

It would appear that the response that's received from Google when querying "https://www.google.com/search?q=${this.currencyAmount}+${this.currencyFrom}+to+${this.currencyTo}+&hl=en" has changed. That results in the converter returning NaN when called with the .convert method.

@artureg
Copy link

artureg commented Jan 23, 2025

Have you found any other working solutions?

@ysrdevs
Copy link

ysrdevs commented Jan 23, 2025

Would be better to target this div instead. Searching 1 USD to 1 CAD it shows the exact conversion rate in code. I'm trying to fix on my end.

<div class="b1hJbf" data-exchange-rate="1.4379549999999999">

@Nneji123
Copy link

Nneji123 commented Feb 1, 2025

If you're using this within a project and don't want to change the code methods much you can use this class instead

const NodeCache = require('node-cache');
const axios = require('axios');

class CurrencyConverter {
  constructor(config = {}) {
    this.apiKey = config.apiKey || process.env.OPENEXCHANGE_API_KEY;
    if (!this.apiKey) {
      throw new Error('OpenExchange API key is required');
    }

    this.baseUrl = 'https://open.exchangerate-api.com/v6';
    this.isDecimalComma = config.isDecimalComma || false;
    this.fromCurrency = null;
    this.toCurrency = null;
    this.amount = null;

    this.cache = new NodeCache();
    this.isRatesCaching = false;
    this.ratesCacheDuration = 3600;
  }

  from(currency) {
    console.log('Setting from currency:', currency);
    this.fromCurrency = currency;
    return this;
  }

  to(currency) {
    console.log('Setting to currency:', currency);
    this.toCurrency = currency;
    return this;
  }

  setAmount(value) {
    // Changed from amount() to setAmount()
    console.log('Setting amount:', value);
    this.amount = value;
    return this;
  }

  async convert(amount = null) {
    if (amount !== null) {
      this.amount = amount;
    }

    if (!this.amount) {
      throw new Error('Amount is required for conversion');
    }

    try {
      const rate = await this.getRates();
      const result = this.amount * rate;
      return this.isDecimalComma ? result.toString().replace('.', ',') : result;
    } catch (error) {
      throw new Error(`Conversion failed: ${error.message}`);
    }
  }

  async getRates() {
    if (!this.fromCurrency || !this.toCurrency) {
      throw new Error('From and To currencies are required');
    }

    const cacheKey = `${this.fromCurrency}-${this.toCurrency}`;

    if (this.isRatesCaching) {
      const cachedRate = this.cache.get(cacheKey);
      if (cachedRate) {
        return cachedRate;
      }
    }

    try {
      const response = await axios.get(
        `${this.baseUrl}/latest/${this.fromCurrency}`,
        {
          params: {
            app_id: this.apiKey
          }
        }
      );

      if (!response.data || !response.data.rates) {
        throw new Error('Invalid response from exchange rate API');
      }

      const rate = response.data.rates[this.toCurrency];

      if (!rate) {
        throw new Error(`Rate not found for ${this.toCurrency}`);
      }

      if (this.isRatesCaching) {
        this.cache.set(cacheKey, rate, this.ratesCacheDuration);
      }

      return rate;
    } catch (error) {
      throw new Error(`Failed to fetch exchange rates: ${error.message}`);
    }
  }

  setupRatesCache(options = {}) {
    this.isRatesCaching = options.isRatesCaching || false;
    this.ratesCacheDuration = options.ratesCacheDuration || 3600;
    return this;
  }
}

module.exports = CurrencyConverter;

The only method that's changed is the amount method which was changed to setAmount.

Here's how I use it in a script:

require('dotenv').config();
const CurrencyConverter = require('./src/utils/currencyConverter');

async function testConverter() {
  try {
    console.log('Creating converter instance...');
    const converter = new CurrencyConverter();

    console.log('Setting up cache...');
    converter.setupRatesCache({
      isRatesCaching: true,
      ratesCacheDuration: 3600
    });

    console.log('Starting conversion...');
    const result = await converter
      .from('NGN')
      .to('USD')
      .setAmount(50000) // Note the change here from .amount to .setAmount
      .convert();

    console.log('Conversion result:', result);
  } catch (error) {
    console.error('Error:', error.message);
  }
}

// Run the tests
testConverter();

Make sure to set the OPENEXCHANGE_API_KEY in your .env file or as an environment variable.

@ysrdevs
Copy link

ysrdevs commented Feb 1, 2025

Ended up setting up a new API on my own server. You guys should try it's not that hard to setup. I have a few endpoints and parameters now.

@paul-shuvo
Copy link
Owner

I tested multiple libraries, but it looks like Google isn’t returning any search results when queried through this one. Using tools like puppeteer might work, but it feels like overkill.

Would be better to target this div instead. Searching 1 USD to 1 CAD it shows the exact conversion rate in code. I'm trying to fix on my end.

<div class="b1hJbf" data-exchange-rate="1.4379549999999999">

@ysrdevs are you getting any Google response?

@paul-shuvo paul-shuvo added the help wanted Extra attention is needed label Feb 13, 2025
@ojhstill
Copy link

ojhstill commented Feb 16, 2025

Happy to help if anyone could provide me some detail on what's happening here. Is it not as simple is targeting a new class or are they dynamically generated? As suggested by @ysrdevs I'm thinking we could target the data-exchange-rate HTML attributes and use that to calculate the value locally.

@paul-shuvo
Copy link
Owner

@ojhstill I'm not getting any HTML response when I try to query through get or request. Did you try with other packages?

@ysrdevs
Copy link

ysrdevs commented Feb 24, 2025

data-exchange-rate works just fine, if we pull this element the package will work. I ended up making a new API myself using data-exchange-rate, it works.

@ysrdevs
Copy link

ysrdevs commented Feb 24, 2025

@paul-shuvo If you want, email me at [email protected] I can share my API with you

@ysrdevs
Copy link

ysrdevs commented Feb 26, 2025

I can open source my API if you guys want, it has to be deployed on a server but it can be a cheap $6 digital ocean server or your own computer at home. Not sure if anyone is interested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

6 participants