新增page Loading的進度條

pnpm add nprogress pnpm add -D @types/nprogress

在pages/_app.tsx新增

import 'nprogress/nprogress.css';
import { useRouter } from 'next/router'; import NProgress from 'nprogress'; import { useEffect } from 'react';
function MyApp({ Component, pageProps }: AppProps) {
	const router = useRouter();
	// Integrate nprogress
	useEffect(() => {
	router.events.on('routeChangeStart', () => NProgress.start());
	router.events.on('routeChangeComplete', () => NProgress.done());
	router.events.on('routeChangeError', () => NProgress.done());
...
	// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

這樣就可以在等待的時候看到藍色進度條了🎉

ref

三種使用Python爬取網頁的方法

第一版: 使用session慢慢爬

s = requests.Session()

第二版: 使用python的並行處理功能

import requests
import concurrent.futures
results = []
# 定義爬蟲任務
def fetch_url(url, session):
    try:
        response = session.get(url)
        try:
            return url, response.status_code, response.json()
        except:
            return url, response.status_code, {}

       
    except requests.RequestException as e:
        return url, None

def fetch(urls):
    with requests.Session() as session:
        with concurrent.futures.ThreadPoolExecutor() as executor:
            # 使用 map 函式來同時執行多個爬蟲任務
            results = executor.map(fetch_url, urls, [session] * len(urls))
    return results

第三版: 直接使用異步處理方式

import asyncio
import aiohttp

async def fetch_url(session, url):
    try:
        async with session.get(url) as response:
            # 在這裡你可以對回應進行任何處理,例如解析HTML,提取資料等。
            # 這裡我們只回傳回應的狀態碼作為範例。
            try:
                data = await response.json()
                return url, response.status, data
            except:
                print("=======================================", url, response.status)
                return url, response.status, {}

    except aiohttp.ClientError as e:
        return url, None, {}
async def fetch_all(urls):
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, url) for url in urls]
        return await asyncio.gather(*tasks)

urls_courses = [
    "https://up.mcuosc.dev/courses/json?page="+str(i) for i in range(200)
]

loop = asyncio.get_event_loop()
results = loop.run_until_complete(fetch_all(urls_courses))

實作ipfs上傳的前端

  1. import package
import { NFTStorage, File, Blob } from 'nft.storage'
const API_KEY = process.env.NFT_STORAGE_API_KEY
const client = new NFTStorage({ token: API_KEY })
function dataURItoBlob(dataURI) {
    // convert base64 to raw binary data held in a string
    // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
    var byteString = atob(dataURI.split(',')[1]);
    // separate out the mime component
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
    // write the bytes of the string to an ArrayBuffer
    var ab = new ArrayBuffer(byteString.length);
    // create a view into the buffer
    var ia = new Uint8Array(ab);
    // set the bytes of the buffer to the correct values
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    // write the ArrayBuffer to a blob, and you're done
    var blob = new Blob([ab], {type: mimeString});
    return blob;  
}
    ...
    const [dataUri, setDataUri] = useState("")
    const [ipfs, setIpfs] = useState("")

    const onChange = (file) => {
        if (!file) {
            setDataUri('');
            return;
        }
        fileToDataUri(file)
            .then(dataUri => {
                setDataUri(dataUri)
            })
    }
    const handle_mint = () => {
        const upload_ipfs  = async() => {
            const img_blob = await dataURItoBlob(dataUri)
            //const img_cid = await client.storeBlob(img_blob)
            const metadata = await client.store({
                name: 'My sweet NFT',
                description: 'Just try to funge it. You can\'t do it.',
                image: img_blob
            })
            console.log(metadata.url)
            setIpfs(metadata.url)
        }
        upload_ipfs()
    }
return (
        <Layout>
           ...
            <img width="100" height="100" src={dataUri} alt="avatar"/>
            <input type="file" onChange={(event) => onChange(event.target.files[0] || null)} ></input>
            <Button onClick={handle_mint}>Create</Button>
            {ipfs}
        </Layout>
    )

Erc 1155 合約

ERC 721

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract MyToken is ERC721, ERC721URIStorage, Ownable {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;

    constructor() ERC721("MyToken", "MTK") {}

    function safeMint(address to, string memory uri) public onlyOwner {
        uint256 tokenId = _tokenIdCounter.current();
        _tokenIdCounter.increment();
        _safeMint(to, tokenId);
        _setTokenURI(tokenId, uri);
    }

    // The following functions are overrides required by Solidity.

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}
  1. safemint
    • to:自己address, uri: https://alanhc.github.io/nft/opensea-example.json 就可以在 testnet opensea看到 其實也可以不用一個一個設置:可以直接設置baseuri :https://ethereum.stackexchange.com/questions/122404/best-way-to-set-metadata-in-erc721-contract-on-production

erc 1155

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC1155, Ownable {
    uint256 public constant Rock = 1;
    uint256 public constant Paper = 2;
    uint256 public constant Scissors = 3;
    constructor() ERC1155("https://alanhc.github.io/nft/erc-1155/{id}.json") {
        _mint(msg.sender, Rock, 1, "");
        _mint(msg.sender, Paper, 1, "");
        _mint(msg.sender, Scissors, 1, "");
    }

    function setURI(string memory newuri) public onlyOwner {
        _setURI(newuri);
    }

    function mint(address account, uint256 id, uint256 amount, bytes memory data)
        public
        onlyOwner
    {
        _mint(account, id, amount, data);
    }

    function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
        public
        onlyOwner
    {
        _mintBatch(to, ids, amounts, data);
    }
}

註記:mint data要設定 0x0000000000000000000000000000000000000000000000000000000000000000

部署我的網站到k8s上

1. 在專案根目錄新增以下檔案

FROM node:16-alpine

ARG NODE_ENV="production"

ENV NODE_ENV=${NODE_ENV}

WORKDIR /app

COPY package*.json ./

RUN yarn install

COPY . .

ENV PORT=3000

EXPOSE 3000

CMD [ "yarn", "start" ]

2. build image

docker build . -t alanhc/alanhc.github.io:latest

0%