VS Code suggested i install Solidity extension which I did. immediately it installed it required that I update my solidity to 0.8.17; I did then I had to update some parts of the code. after I did, I tested on remix and it worked. Back on vs code now and I've been trying to compile but it is not compiling.It creates the 'build' folder but doesn't write any JSON files in it.
Campaign.sol file:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;
contract CampaignFactory {
address[] public deployedCampaigns;
function createCampaign(uint minimum) public {
Campaign newCampaign = new Campaign(minimum, msg.sender);
deployedCampaigns.push(address(newCampaign));
}
function getDeployedCampaigns() public view returns (address[] memory) {
return deployedCampaigns;
}
}
contract Campaign {
struct Request {
string description;
uint value;
address payable recipient;
bool complete;
uint approvalCount;
mapping(address => bool) approvals;
}
Request[] public requests;
address public manager;
uint public minimumContribution;
mapping(address => bool) public approvers;
uint public approversCount;
modifier restricted() {
require(msg.sender == manager);
_;
}
constructor (uint minimum, address creator) {
manager = creator;
minimumContribution = minimum;
}
function contribute() public payable {
require(msg.value > minimumContribution);
approvers[msg.sender] = true;
approversCount++;
}
function createRequest(string memory description, uint value, address payable recipient) public restricted {
Request storage newRequest = requests.push();
newRequest.description = description;
newRequest.value = value;
newRequest.recipient = recipient;
newRequest.complete = false;
newRequest.approvalCount = 0;
}
function approveRequest(uint index) public {
Request storage request = requests[index];
require(approvers[msg.sender]);
require(!request.approvals[msg.sender]);
request.approvals[msg.sender] = true;
request.approvalCount++;
}
function finalizeRequest(uint index) public restricted {
Request storage request = requests[index];
require(request.approvalCount > (approversCount / 2));
require(!request.complete);
request.recipient.transfer(request.value);
request.complete = true;
}
function getSummary() public view returns (
uint, uint, uint, uint, address
) {
return(
minimumContribution,
address(this).balance,
requests.length,
approversCount,
manager
);
}
function getRequestsCount() public view returns (uint) {
return requests.length;
}
}
compile.js file
const path = require("path");
const solc = require("solc");
const fs = require("fs-extra");
const buildPath = path.resolve(__dirname, "build");
fs.removeSync(buildPath);
const campaignPath = path.resolve(__dirname, "contracts", "Campaign.sol");
const source = fs.readFileSync(campaignPath, "utf8");
const output = solc.compile(source, 1).contracts;
fs.ensureDirSync(buildPath);
for (let contract in output) {
fs.outputJsonSync(
path.resolve(buildPath, contract.replace(":", "") + ".json"),
output[contract]
);
}
Related
i'm learning blockchain dev and now i'm trying to mint an NFT, the process is ok but the problem is that metadata are not showed in the wallet or opensea.
This is the contract
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.17;
import '#openzeppelin/contracts/token/ERC721/ERC721.sol';
import '#openzeppelin/contracts/access/Ownable.sol';
import "#openzeppelin/contracts/utils/Counters.sol";
contract NFT is ERC721, Ownable {
uint256 public mintPrice;
uint256 public maxPerWallet;
uint256 public totalSupply;
bool public isPublicMintEnabled;
string internal baseTokenUri;
address payable public withdrawWallet;
mapping (address => uint256) public walletMints;
mapping(uint256 => string) private _tokenURIs;
Counters.Counter private _tokenIds;
using Counters for Counters.Counter;
using Strings for uint256;
constructor() payable ERC721('NFT', 'NFT') {
mintPrice = 0.0004 ether;
maxPerWallet = 3;
// Set withdraw wallet address
}
function setIsPublicMintEnabled(bool isPublicMintEnabled_) external onlyOwner {
isPublicMintEnabled = isPublicMintEnabled_;
}
function setBaseTokenUri(string calldata baseTokenUri_) external onlyOwner {
baseTokenUri = baseTokenUri_;
}
function tokenURI(uint256 tokenId_) public view override returns (string memory) {
require(_exists(tokenId_), 'Token does not exist!');
return string(abi.encodePacked(baseTokenUri, Strings.toString(tokenId_), ".json"));
}
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual
{
_tokenURIs[tokenId] = _tokenURI;
}
function withDraw() external onlyOwner {
(bool success, ) = withdrawWallet.call{ value: address(this).balance } ('');
require(success, 'Withdraw failed');
}
function mint(string memory uri) public payable returns (uint256) {
require(isPublicMintEnabled, 'Mint is not enabled');
require(msg.value == mintPrice, 'Wrong mint value');
require(walletMints[msg.sender] + 1 <= maxPerWallet, 'Exceed max quantity per wallet');
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(msg.sender, newItemId);
_setTokenURI(newItemId, uri);
return newItemId;
}
}
And this is the mint function on the mint website
const mintNFT = async (nft) => {
setMinting(true)
const mintAmount = 1
const isConnected = Boolean(accounts[0])
if (!isConnected) {
alert('Non sei connesso al tuo Wallet')
setMinting(false)
return
}
var nftParsed = JSON.parse(nft.metadata)
if (window.ethereum) {
// Connect to blockchain
const provider = new providers.Web3Provider(window.ethereum)
const signer = provider.getSigner()
const contract = new Contract(
address,
NFT.abi, // Implement
signer
)
const imageFile = await dataUrlToFile(nftParsed.image, "img.png")
const nftstorage = new NFTStorage({ token: NFT_STORAGE_KEY })
const storage = await nftstorage.store({
image: imageFile,
name: nftParsed.name,
description: 'prova'
})
if (storage) {
try {
const response = await contract.mint(storage.url, {
value: ethers.utils.parseEther((0.0004).toString())
})
console.log(response)
} catch (e) {
console.error(e)
alert("Sorry, error while minting your NFT")
setMinting(false)
}
} else {
alert("Mint problems")
setMinting(false)
}
setMinting(false)
}
}
This code convert dataurl (format for nft saved in db) to image
async function dataUrlToFile(dataUrl, fileName) {
const res = await fetch(dataUrl);
const blob = await res.blob();
return new File([blob], fileName, { type: 'image/png' });
}
In first try, i successfully created nft with metadata, but now using a min website seems to be impossible, the time that it worked the image was stored in a directory and not in a dataurl format.
Hope someone can help,
Thanks
Hello I am new to Smart Contract development, for a few days I try to get this working, but no luck. I hope someone can help me. I try to communicate to a Smart Contract deployed to BSC https://testnet.bscscan.com/address/0x2ED1c3c1Fc6646F321cf546a892684E946435CE9 see the source code below.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract FundMe {
mapping(address => uint256) public addressToAmountFunded;
address[] public funders;
address public owner;
AggregatorV3Interface internal priceFeed;
uint balance;
// if you're following along with the freecodecamp video
// Please see https://github.com/PatrickAlphaC/fund_me
// to get the starting solidity contract code, it'll be slightly different than this!
constructor(address _priceFeed) {
priceFeed = AggregatorV3Interface(_priceFeed);
owner = msg.sender;
}
function fund() public payable {
uint256 mimimumUSD = 50 * 10**18;
require(
getConversionRate(msg.value) >= mimimumUSD,
"You need to spend more ETH!"
);
addressToAmountFunded[msg.sender] += msg.value;
balance += msg.value;
funders.push(msg.sender);
}
function getVersion() public view returns (uint256) {
return priceFeed.version();
}
function getPrice() public view returns (uint256) {
(, int price, , , ) = priceFeed.latestRoundData();
return uint256(price * 10000000000);
}
// 1000000000
function getConversionRate(uint256 ethAmount)
public
view
returns (uint256)
{
uint256 ethPrice = getPrice();
uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000;
return ethAmountInUsd;
}
function getEntranceFee() public view returns (uint256) {
// mimimumUSD
uint256 mimimumUSD = 50 * 10**18;
uint256 price = getPrice();
uint256 precision = 1 * 10**18;
return (mimimumUSD * precision) / price;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function withdraw() public payable onlyOwner {
payable(msg.sender).transfer(balance);
for (
uint256 funderIndex = 0;
funderIndex < funders.length;
funderIndex++
) {
address funder = funders[funderIndex];
addressToAmountFunded[funder] = 0;
}
funders = new address[](0);
}
}
I deployed the smart contract with truffle, with the following migration script
const FundMe = artifacts.require("FundMe");
const BINANCE_BNB_USD_PRICE_FEED = '0x0567F2323251f0Aab15c8dFb1967E4e8A7D42aeE';
module.exports = async (deployer, network, [defaultAccount]) => {
let priceFeedAddress = BINANCE_BNB_USD_PRICE_FEED
try {
await deployer.deploy(FundMe, BINANCE_BNB_USD_PRICE_FEED, { from: defaultAccount })
} catch (err) {
console.error(err)
}
}
I try to call getPrice() that communicates to chainlink to get the latest price of BNB/USDT.
Here is the Javascript
const getContract = () =>
new Promise(async (resolve, reject) => {
const contract = await fetch('./build/contracts/FundMe.json')
const Contract = await contract.json()
let provider = await detectEthereumProvider()
if (provider) {
await provider.request({ method: 'eth_requestAccounts' })
const networkId = await provider.request({ method: 'net_version' })
provider = new ethers.providers.Web3Provider(provider)
const signer = provider.getSigner()
showAddress(signer)
const contract = new ethers.Contract(
Contract.networks[networkId].address,
Contract.abi,
signer,
)
resolve(contract)
return
}
reject('Install Metamask')
})
const showAddress = async (signer) => {
address = await signer.getAddress()
const connectButton = document.getElementById('connect')
connectButton.innerText = address
}
const getPrice = async (contract) => {
console.log('contract', contract)
const price = await contract.getPrice()
console.log('price', price)
const priceContainer = document.getElementById('price')
priceContainer.innerText = price
}
const init = async () => {
const contract = await getContract()
getPrice(contract)
}
const fundButton = document.getElementById('fund')
fundButton.addEventListener('click', async () => {
const fundMe = await getContract()
})
init()
I get the following error in the browser console and have no idea whats the cause.
Your deploy script passing the 0x056... address as the priceFeed param of the constructor.
So the getPrice() contract function is then trying to call the latestRoundData() on the 0x056... address, expecting a response.
However, your contract is deployed on the testnet, and there's no contract on the 0x056... address on the testnet (link) to return a value, which causes the "main" call to revert.
I am a beginner in blockchain programming and I am not able to understand why I am getting an error while trying to solidity function using Web3 and Ganache.
const PetList = require('./build/contracts/PetList.json')
const fs = require('fs')
const Web3 = require('web3')
const abi = fs.readFileSync("build/contracts/PetList.json").toString().trim();
// Ganache Blockchain
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));
web3.eth.net.isListening()
.then(() => console.log('Web3 is connected'))
.catch(e => console.log('Wow. Something went wrong'));
var setUpContract = async function( ){
await web3.eth.net.getId().then((networkId) => {
const networkData = PetList.networks[networkId]
console.log("Setting up contract...")
if(networkData){
return petList = new web3.eth.Contract(PetList.abi, networkData.address)
}
})
acc = await web3.eth.getAccounts()
currentAccount = acc[0]
console.log("Account: ", acc[0])
}
async function start(){
await setUpContract()
await addPet()
}
var addPet = async function(){
console.log(await getPetCount())
return results = await petList.methods.addPet('Zippo', 'Dog').send({from: currectAccount})
}
start()
pragma solidity ^0.5.0;
contract PetList{
uint public petCount = 0;
mapping (uint => Pet) public pets;
struct Pet{
uint id;
string name;
string tag;
}
event PetAdded(
uint id,
string name,
string tag
);
function addPet(string memory _name, string memory _tag) public {
require(bytes(_name).length > 0, "INVALID TAG");
require(bytes(_tag).length > 0, "INVALID NAME");
petCount++;
pets[petCount] = Pet(petCount, _name, _tag);
emit PetAdded(petCount, _name, _tag);
}
}
I also used .send() without any parameters and it gave me an error saying No "from" address specified in neither the given options, nor the default options.
To make a function receive ether you must have a fallback function or add payable modifier
So you can change your code to the following
function addPet(string memory _name, string memory _tag) public payable
I have this error:
.../node_modules/truffle-expect/index.js:3
expected_keys.forEach(function(key) {
^
Error: Expected parameter 'solc' not passed to function.
when I try to use truffle-solidity-loader using webpack. Any idea how to fix it? Thank you.
UPDATE:
The smart contract:
pragma solidity ^0.5.0;
contract ToDo {
struct Task {
uint id;
uint date;
string content;
string author;
bool done;
}
uint lastTaskId;
mapping(uint => Task) tasks;
uint[] taskIds;
constructor () public{
lastTaskId = 0;
}
event TaskCreated(uint id, uint date, string content, string author, bool done);
function createTask(string memory _content, string memory _author) public {
lastTaskId++;
tasks[lastTaskId] = Task(lastTaskId, now, _content, _author, false);
taskIds.push(lastTaskId);
emit TaskCreated(lastTaskId, now, _content, _author, false);
}
function getTask(uint id) taskExists(id) public view returns (uint, uint, string memory, string memory, bool) {
return(
id,
tasks[id].date,
tasks[id].content,
tasks[id].author,
tasks[id].done
);
}
function getTaskIds() view public returns (uint[] memory) {
return taskIds;
}
// function getTaskFixtures(uint _id) public view returns(uint,uint,string,string,bool) {
// return (0, now, "Create more tutorials for ETB", "Julien", false);
// }
modifier taskExists(uint id){
if(tasks[id].id == 0){
revert();
}
_;
}
}
The index.js:
import artifact from '../../contracts/ToDo.sol';
import Web3 from 'web3';
import TruffleContract from 'truffle-contract';
// import config from './config.js';
console.log('loaded');
const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:7545'));
const abstraction = new TruffleContract(artifact);
abstraction.setProvider(web3.currentProvider);
const network = Object.keys(artifact.networks)[0];
const address = artifact.networks[network].address;
abstraction.at(address)
.then((todo) => {
todo.getTaskIds()
.then((taskIds) => {
console.log(taskIds);
});
});
web3.eth.getAccounts(console.log);
The server:
const express = require('express');
const app = express();
const PORT = 3000;
//Serve static assets (js, css, ...)
app.use(express.static('app'));
//Serve contract artifact files (ex: ToDo.json)
app.use(express.static('build/contracts'));
//Serve index.html
app.get('/', (req, res) => {
res.sendFile(`${__dirname}/app/index.html`);
});
//If anything else is requested that's an error
app.get('*', (req, res) => {
res.status(404);
res.send('Oops... this URL does not exist');
});
//Start the server
app.listen(PORT, () => {
console.log(`ETB Ethereum ToDo List App running on port ${PORT}...`);
});
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
using Discord.Commands;
using Discord;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;
using NadekoBot.Services;
using System.Threading;
using System.Collections.Generic;
using NadekoBot.Services.Database.Models;
using System.Net.Http;
using NadekoBot.Attributes;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using NLog;
using NadekoBot.Extensions;
using System.Diagnostics;
namespace NadekoBot.Modules.Searches
{
public partial class Searches
{
public class StreamStatus
{
public bool IsLive { get; set; }
public string ApiLink { get; set; }
public string Views { get; set; }
public string Game { get; set; }
public string Status { get; set;}
}
public class HitboxResponse {
public bool Success { get; set; } = true;
[JsonProperty("media_is_live")]
public string MediaIsLive { get; set; }
public bool IsLive => MediaIsLive == "1";
[JsonProperty("media_views")]
public string Views { get; set; }
}
public class TwitchResponse
{
public string Error { get; set; } = null;
public bool IsLive => Stream != null;
public StreamInfo Stream { get; set; }
public class StreamInfo
{
public int Viewers { get; set; }
public string Game { get; set; }
public ChannelInfo Channel { get; set;}
public class ChannelInfo {
public string Status { get; set; )
}
}
}
public class BeamResponse
{
public string Error { get; set; } = null;
[JsonProperty("online")]
public bool IsLive { get; set; }
public int ViewersCurrent { get; set; }
}
public class StreamNotFoundException : Exception
{
public StreamNotFoundException(string message) : base("Stream '" + message + "' not found.")
{
}
}
[Group]
public class StreamNotificationCommands : ModuleBase
{
private static Timer checkTimer { get; }
private static ConcurrentDictionary<string, StreamStatus> oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
private static ConcurrentDictionary<string, StreamStatus> cachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
private static Logger _log { get; }
private static bool FirstPass { get; set; } = true;
static StreamNotificationCommands()
{
_log = LogManager.GetCurrentClassLogger();
checkTimer = new Timer(async (state) =>
{
oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>(cachedStatuses);
cachedStatuses.Clear();
IEnumerable<FollowedStream> streams;
using (var uow = DbHandler.UnitOfWork())
{
streams = uow.GuildConfigs.GetAllFollowedStreams();
}
await Task.WhenAll(streams.Select(async fs =>
{
try
{
var newStatus = await GetStreamStatus(fs).ConfigureAwait(false);
if (FirstPass)
{
return;
}
StreamStatus oldStatus;
if (oldCachedStatuses.TryGetValue(newStatus.ApiLink, out oldStatus) &&
(oldStatus.IsLive != newStatus.IsLive)
{
var server = NadekoBot.Client.GetGuild(fs.GuildId);
if (server == null)
return;
var channel = server.GetTextChannel(fs.ChannelId);
if (channel == null)
return;
try
{
var msg = await channel.EmbedAsync(fs.GetEmbed(newStatus)).ConfigureAwait(false);
}
catch { }
}
}
catch { }
}));
FirstPass = false;
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(60));
}
private static async Task<StreamStatus> GetStreamStatus(FollowedStream stream, bool checkCache = true)
{
string response;
StreamStatus result;
switch (stream.Type)
{
case FollowedStream.FollowedStreamType.Hitbox:
var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username.ToLowerInvariant()}";
if (checkCache && cachedStatuses.TryGetValue(hitboxUrl, out result))
return result;
using (var http = new HttpClient())
{
response = await http.GetStringAsync(hitboxUrl).ConfigureAwait(false);
}
var hbData = JsonConvert.DeserializeObject<HitboxResponse>(response);
if (!hbData.Success)
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
result = new StreamStatus()
{
IsLive = hbData.IsLive,
ApiLink = hitboxUrl,
Views = hbData.Views
};
cachedStatuses.AddOrUpdate(hitboxUrl, result, (key, old) => result);
return result;
case FollowedStream.FollowedStreamType.Twitch:
var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username.ToLowerInvariant())}?client_id=67w6z9i09xv2uoojdm9l0wsyph4hxo6";
if (checkCache && cachedStatuses.TryGetValue(twitchUrl, out result))
return result;
using (var http = new HttpClient())
{
response = await http.GetStringAsync(twitchUrl).ConfigureAwait(false);
}
var twData = JsonConvert.DeserializeObject<TwitchResponse>(response);
if (twData.Error != null)
{
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
}
result = new StreamStatus()
{
IsLive = twData.IsLive,
ApiLink = twitchUrl,
Views = twData.Stream?.Viewers.ToString() ?? "0"
Game = twData.Stream?.Game,
Status = twData.Stream?.Channel?.Status
};
cachedStatuses.AddOrUpdate(twitchUrl, result, (key, old) => result);
return result;
case FollowedStream.FollowedStreamType.Beam:
var beamUrl = $"https://beam.pro/api/v1/channels/{stream.Username.ToLowerInvariant()}";
if (checkCache && cachedStatuses.TryGetValue(beamUrl, out result))
return result;
using (var http = new HttpClient())
{
response = await http.GetStringAsync(beamUrl).ConfigureAwait(false);
}
var bmData = JsonConvert.DeserializeObject<BeamResponse>(response);
if (bmData.Error != null)
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
result = new StreamStatus()
{
IsLive = bmData.IsLive,
ApiLink = beamUrl,
Views = bmData.ViewersCurrent.ToString()
};
cachedStatuses.AddOrUpdate(beamUrl, result, (key, old) => result);
return result;
default:
break;
}
return null;
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)]
public async Task Hitbox([Remainder] string username) =>
await TrackStream((ITextChannel)Context.Channel, username, FollowedStream.FollowedStreamType.Hitbox)
.ConfigureAwait(false);
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)]
public async Task Twitch([Remainder] string username) =>
await TrackStream((ITextChannel)Context.Channel, username, FollowedStream.FollowedStreamType.Twitch)
.ConfigureAwait(false);
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)]
public async Task Beam([Remainder] string username) =>
await TrackStream((ITextChannel)Context.Channel, username, FollowedStream.FollowedStreamType.Beam)
.ConfigureAwait(false);
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task ListStreams()
{
IEnumerable<FollowedStream> streams;
using (var uow = DbHandler.UnitOfWork())
{
streams = uow.GuildConfigs
.For(Context.Guild.Id,
set => set.Include(gc => gc.FollowedStreams))
.FollowedStreams;
}
if (!streams.Any())
{
await Context.Channel.SendConfirmAsync("You are not following any streams on this server.").ConfigureAwait(false);
return;
}
var text = string.Join("\n", await Task.WhenAll(streams.Select(async snc =>
{
var ch = await Context.Guild.GetTextChannelAsync(snc.ChannelId);
return $"`{snc.Username}`'s stream on **{(ch)?.Name}** channel. 【`{snc.Type.ToString()}`】";
})));
await Context.Channel.SendConfirmAsync($"You are following **{streams.Count()}** streams on this server.\n\n" + text).ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
[RequireUserPermission(GuildPermission.ManageMessages)]
public async Task RemoveStream(FollowedStream.FollowedStreamType type, [Remainder] string username)
{
username = username.ToLowerInvariant().Trim();
var fs = new FollowedStream()
{
ChannelId = Context.Channel.Id,
Username = username,
Type = type
};
bool removed;
using (var uow = DbHandler.UnitOfWork())
{
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(gc => gc.FollowedStreams));
removed = config.FollowedStreams.Remove(fs);
if (removed)
await uow.CompleteAsync().ConfigureAwait(false);
}
if (!removed)
{
await Context.Channel.SendErrorAsync("No such stream.").ConfigureAwait(false);
return;
}
await Context.Channel.SendConfirmAsync($"Removed `{username}`'s stream ({type}) from notifications.").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
[RequireContext(ContextType.Guild)]
public async Task CheckStream(FollowedStream.FollowedStreamType platform, [Remainder] string username)
{
var stream = username?.Trim();
if (string.IsNullOrWhiteSpace(stream))
return;
try
{
var streamStatus = (await GetStreamStatus(new FollowedStream
{
Username = stream,
Type = platform,
}));
if (streamStatus.IsLive)
{
await Context.Channel.SendConfirmAsync($"Streamer {username} is online with {streamStatus.Views} viewers.");
}
else
{
await Context.Channel.SendConfirmAsync($"Streamer {username} is offline.");
}
}
catch
{
await Context.Channel.SendErrorAsync("No channel found.");
}
}
private static async Task TrackStream(ITextChannel channel, string username, FollowedStream.FollowedStreamType type)
{
username = username.ToLowerInvariant().Trim();
var fs = new FollowedStream
{
GuildId = channel.Guild.Id,
ChannelId = channel.Id,
Username = username,
Type = type,
};
StreamStatus status;
try
{
status = await GetStreamStatus(fs).ConfigureAwait(false);
}
catch
{
await channel.SendErrorAsync("Stream probably doesn't exist.").ConfigureAwait(false);
return;
}
using (var uow = DbHandler.UnitOfWork())
{
uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.FollowedStreams))
.FollowedStreams
.Add(fs);
await uow.CompleteAsync().ConfigureAwait(false);
}
await channel.EmbedAsync(fs.GetEmbed(status), $"🆗 I will notify this channel when status changes.").ConfigureAwait(false);
}
}
}
public static class FollowedStreamExtensions
{
public static EmbedBuilder GetEmbed(this FollowedStream fs, Searches.StreamStatus status)
{
var embed = new EmbedBuilder().WithTitle(fs.Username)
.WithUrl(fs.GetLink())
.WithThumbnailUrl(fs.GetLink())
.WithDescription(status.Status)
.AddField(efb => efb.WithName("Status")
.WithValue(status.IsLive ? "Online" : "Offline")
.WithIsInline(true))
.AddField(efb => efb.WithName("Viewers")
.WithValue(status.IsLive ? status.Views : "-")
.WithIsInline(true))
.AddField(efb => efb.WithName("Game">
.WithValue(status.Game)
.WithIsInlin(true))
.AddField(efb => efb.WithName("Platform")
.WithValue(fs.Type.ToString())
.WithIsInline(true))
.WithColor(status.IsLive ? "NadekoBot.OkColor" : "NadekoBot.ErrorColor");
return embed;
}
public static string GetLink(this FollowedStream fs) {
if (fs.Type == FollowedStream.FollowedStreamType.Hitbox)
return $"http://www.hitbox.tv/{fs.Username}/";
else if (fs.Type == FollowedStream.FollowedStreamType.Twitch)
return $"http://www.twitch.tv/{fs.Username}/";
else if (fs.Type == FollowedStream.FollowedStreamType.Beam)
return $"https://beam.pro/{fs.Username}/";
else
return "??";
}
}
}
I'm attempting to get this discord bot to announce when someone streaming on Twitch goes Live by amending its code to give me more information (ie Game and Status) but I keep getting an error that I can't for the life of me find and fix! I was told the issue is between coding on a PC and coding on a Mac? Not sure that's 100% accurate. Can someone please run this code and help me get this to work properly? Thanks!