# Path: rss/cleanup.py
# def html_to_text(html_data):  # https://stackoverflow.com/a/7778368
#     """Converts HTML to plain text (stripping tags and converting entities).
#     >>> html_to_text('<a href="#">Demo<!--...--> <em>(&not; \u0394&#x03b7;&#956;&#x03CE;)</em></a>')
#     'Demo (\xac \u0394\u03b7\u03bc\u03ce)'
# 
#     "Plain text" doesn't mean result can safely be used as-is in HTML.
#     >>> html_to_text('&lt;script&gt;alert("Hello");&lt;/script&gt;')
#     '<script>alert("Hello");</script>'
# 
#     Always use html.escape to sanitize text before using in an HTML context!
# 
#     HTMLParser will do its best to make sense of invalid HTML.
#     >>> html_to_text('x < y &lt z <!--b')
#     'x < y < z '
# 
#     Unrecognized named entities are included as-is. '&apos;' is recognized,
#     despite being XML only.
#     >>> html_to_text('&nosuchentity; &apos; ')
#     "&nosuchentity; ' "
#     """
#     html_data = WhitespaceHandler.sub("\n", html_data)
#     s = HTMLTextExtractor()
#     s.feed(html_data)
#     return s.get_text()
# 
# Path: rss/converters.py
# class FieldAndTerm(NamedTuple):
#     field: str
#     term: str
# 
#     @classmethod
#     async def convert(cls, ctx: commands.Context, arg: str) -> FieldAndTerm:
# 
#         try:
#             field, term = arg.casefold().split(maxsplit=1)
#         except ValueError:
#             raise commands.BadArgument("Must provide a field and a term to match")
# 
#         return cls(field, term)
# 
# class NonEveryoneRole(discord.Role):
#     @classmethod
#     async def convert(cls, ctx: commands.Context, arg: str) -> discord.Role:
#         role: discord.Role = await _role_converter.convert(ctx, arg)
#         if role.is_default():
#             raise commands.BadArgument("You can't set this for the everyone role")
#         return role
# 
# class TriState:
#     def __init__(self, state):
#         self.state = state
# 
#     @classmethod
#     async def convert(cls, ctx, arg):
#         return cls(_tristate(arg))


import asyncio
import logging
import string
import urllib.parse
import aiohttp
import discord
import feedparser
from datetime import datetime
from functools import partial
from types import MappingProxyType
from typing import Any, Dict, Generator, List, Optional, cast
from bs4 import BeautifulSoup as bs4
from redbot.core import checks, commands
from redbot.core.config import Config
from redbot.core.utils.chat_formatting import box, pagify
from .cleanup import html_to_text
from .converters import FieldAndTerm, NonEveryoneRole, TriState
                for page in page_gen:
                    await ctx.send(page)
            finally:
                page_gen.close()

    @rss.command(name="remove")
    async def remove_feed(
        self, ctx, name: str, channel: Optional[discord.TextChannel] = None
    ):
        """
        removes a feed from the current channel, or from a provided channel

        If the feed is currently being fetched, there may still be a final update
        after this.
        """
        channel = channel or ctx.channel
        async with self.config.channel(channel).feeds() as feeds:
            if name not in feeds:
                await ctx.send(f"No feed named {name} in {channel.mention}.")
                return

            del feeds[name]

        await ctx.tick()

    @rss.command(name="embed")
    async def set_embed(
        self,
        ctx,
        name: str,

# Path: rss/cleanup.py
# def html_to_text(html_data):  # https://stackoverflow.com/a/7778368
#     """Converts HTML to plain text (stripping tags and converting entities).
#     >>> html_to_text('<a href="#">Demo<!--...--> <em>(&not; \u0394&#x03b7;&#956;&#x03CE;)</em></a>')
#     'Demo (\xac \u0394\u03b7\u03bc\u03ce)'
# 
#     "Plain text" doesn't mean result can safely be used as-is in HTML.
#     >>> html_to_text('&lt;script&gt;alert("Hello");&lt;/script&gt;')
#     '<script>alert("Hello");</script>'
# 
#     Always use html.escape to sanitize text before using in an HTML context!
# 
#     HTMLParser will do its best to make sense of invalid HTML.
#     >>> html_to_text('x < y &lt z <!--b')
#     'x < y < z '
# 
#     Unrecognized named entities are included as-is. '&apos;' is recognized,
#     despite being XML only.
#     >>> html_to_text('&nosuchentity; &apos; ')
#     "&nosuchentity; ' "
#     """
#     html_data = WhitespaceHandler.sub("\n", html_data)
#     s = HTMLTextExtractor()
#     s.feed(html_data)
#     return s.get_text()
# 
# Path: rss/converters.py
# class FieldAndTerm(NamedTuple):
#     field: str
#     term: str
# 
#     @classmethod
#     async def convert(cls, ctx: commands.Context, arg: str) -> FieldAndTerm:
# 
#         try:
#             field, term = arg.casefold().split(maxsplit=1)
#         except ValueError:
#             raise commands.BadArgument("Must provide a field and a term to match")
# 
#         return cls(field, term)
# 
# class NonEveryoneRole(discord.Role):
#     @classmethod
#     async def convert(cls, ctx: commands.Context, arg: str) -> discord.Role:
#         role: discord.Role = await _role_converter.convert(ctx, arg)
#         if role.is_default():
#             raise commands.BadArgument("You can't set this for the everyone role")
#         return role
# 
# class TriState:
#     def __init__(self, state):
#         self.state = state
# 
#     @classmethod
#     async def convert(cls, ctx, arg):
#         return cls(_tristate(arg))


# Path: rss/core.py
import asyncio
import logging
import string
import urllib.parse
import aiohttp
import discord
import feedparser
from datetime import datetime
from functools import partial
from types import MappingProxyType
from typing import Any, Dict, Generator, List, Optional, cast
from bs4 import BeautifulSoup as bs4
from redbot.core import checks, commands
from redbot.core.config import Config
from redbot.core.utils.chat_formatting import box, pagify
from .cleanup import html_to_text
from .converters import FieldAndTerm, NonEveryoneRole, TriState

                for page in page_gen:
                    await ctx.send(page)
            finally:
                page_gen.close()

    @rss.command(name="remove")
    async def remove_feed(
        self, ctx, name: str, channel: Optional[discord.TextChannel] = None
    ):
        """
        removes a feed from the current channel, or from a provided channel

        If the feed is currently being fetched, there may still be a final update
        after this.
        """
        channel = channel or ctx.channel
        async with self.config.channel(channel).feeds() as feeds:
            if name not in feeds:
                await ctx.send(f"No feed named {name} in {channel.mention}.")
                return

            del feeds[name]

        await ctx.tick()

    @rss.command(name="embed")
    async def set_embed(
        self,
        ctx,
        name: str,

        setting: TriState,