Coder Social home page Coder Social logo

khoben / telemirror Goto Github PK

View Code? Open in Web Editor NEW
201.0 8.0 99.0 256 KB

Telegram message forwarder (client API)

License: GNU General Public License v3.0

Python 99.57% Shell 0.08% Procfile 0.02% Dockerfile 0.34%
python telegram mirroring telethon heroku forwarder telegram-bot telegram-forwarder telegram-forward-bot

telemirror's Introduction

Telegram message forwarder (client API)

Functionality

  • Live forwarding and updating messages
  • Source and target channels/chats/topics (one-to-one, many-to-one, many-to-many) mapping
  • Incoming message filters: word replacing, forward formating, skipping by keyword and more

Prepare

  1. Create Telegram App

  2. Obtain API_ID and API_HASH

    Telegram API Credentials

  3. Get SESSION_STRING

    SESSION_STRING can be obtained by running login.py with provided API_ID and API_HASH environment variables. ❗ DON'T USE your own account.

  4. Setup Postgres database or use InMemoryDatabase with USE_MEMORY_DB=true parameter in .env file

  5. Fill .env with your data

    .env-example contains the minimum environment configuration to run with an in-memory database.

    .env overview
    ###########################
    #    App configuration    #
    ###########################
    
    # Telegram app ID
    API_ID=test
    # Telegram app hash
    API_HASH=test
    # Telegram session string (telethon session, see login.py in root directory)
    SESSION_STRING=test
    # Use an in-memory database instead of Postgres DB (true or false). Defaults to false
    USE_MEMORY_DB=false
    # Postgres credentials
    DATABASE_URL=postgres://user:pass@host/dbname
    # or
    DB_NAME=test
    DB_USER=test
    DB_HOST=test
    DB_PASS=test
    # Logging level (debug, info, warning, error or critical). Defaults to info
    LOG_LEVEL=info
  6. Setup mirror forwarding config:

    mirror.config.yml-example contains an example config: to set up a filter, specify the name of the filter (should be accessable from ./telemirror/messagefilters) and pass named parameters with the same types but in yaml syntax. Example:

    - ForwardFormatFilter:  # Filter name under telemirror/messagefilters
        # Filter string argument
        format: "{message_text}\n\nForwarded from [{channel_name}]({message_link})"
    
    - SkipUrlFilter:
        skip_mention: false # Filter bool argument
    
    - UrlMessageFilter:
        blacklist: !!set    # Filter set argument
            ? t.me
            ? google.com

    ./.configs/mirror.config.yml or .env (limited) can be used to configure mirroring:

    ./.configs/mirror.config.yml mirroring config overview
    # (Optional) Global filters, will be applied in order
    filters:
      - ForwardFormatFilter: # Filter name under ./telemirror/messagefilters
          format: ""           # Filters arguments
      - EmptyMessageFilter
      - UrlMessageFilter:
          blacklist: !!set
            ? t.me
      - SkipUrlFilter:
          skip_mention: false
    
    # (Optional) Global settings
    disable_edit: true
    disable_delete: true
    mode: copy # or forward
    
    # (Required) Mirror directions
    directions:
      - from: [-1001, -1002, -1003]
        to: [-100203]
    
      - from: [-1000#3] # forwards from topic to topic
        to: [-1001#4]
    
      - from: [-100226]
        to: [-1006, -1008]
        # Overwrite global settings
        disable_edit: false
        disable_delete: false
        mode: forward
        # Overwrite global filters
        filters:
          - UrlMessageFilter:
              blacklist: !!set
                ? t.me
          - KeywordReplaceFilter:
              keywords:
                "google.com": "bing.com"
              regex: false # treat keywords as plain text
          - SkipWithKeywordsFilter:
              keywords: !!set
                ? "stopword"
              regex: true # treat keywords as regex expr
    .env mirroring config overview
    ###############################################
    #    Setup directions and filters from env    #
    ###############################################
    
    # Mapping between source and target channels/chats
    # Channel/chat id can be fetched by using @messageinformationsbot telegram bot
    # Channel id should be prefixed with -100
    # [id1, id2, id3:id4] means send messages from id1, id2, id3 to id4
    # id5:id6 means send messages from id5 to id6
    # [id1, id2, id3:id4];[id5:id6] semicolon means AND
    CHAT_MAPPING=[-100999999,-100999999,-100999999:-1009999999];
    
    # (Optional) YAML filter configuration thru single-lined env string (new lines (\n) should be replaced to \\n), other filter settings from env will be ignored
    YAML_CONFIG_ENV=
    
    # Remove URLs from incoming messages (true or false). Defaults to false
    REMOVE_URLS=false
    # Comma-separated list of URLs to remove (reddit.com,youtube.com)
    REMOVE_URLS_LIST=google.com,twitter.com
    # Comma-separated list of URLs to exclude from removal (google.com,twitter.com).
    # Will be applied after the REMOVE_URLS_LIST
    REMOVE_URLS_WL=youtube.com,youtu.be,vk.com,twitch.tv,instagram.com
    # Disable mirror message deleting (true or false). Defaults to false
    DISABLE_DELETE=false
    # Disable mirror message editing (true or false). Defaults to false
    DISABLE_EDIT=false

    ❓ Channels ID can be fetched by using Telegram bot.

    ❗ Note: never push your .env/.yml files with real crendential to a public repo. Use a separate branch (eg, heroku-branch) with .env/.yml files to push to git-based deployment system like Heroku.

  7. Make sure the account has joined source and target channels

  8. Be careful with forwards from channels with RESTRICTED SAVING CONTENT. It may lead to an account ban

Deploy

Heroku

Deploy

or via CLI:

  1. Clone project

    git clone https://github.com/khoben/telemirror.git
  2. Create new heroku app within Heroku CLI

    heroku create {your app name}
  3. Add heroku remote

    heroku git:remote -a {your app name}
  4. Set environment variables to your heroku app from .env by running bash script

    ./set_heroku_env.bash
  5. Upload on heroku host

    git push heroku master
  6. Start heroku app

    heroku ps:scale web=1

Keep up-to-date with Heroku

If you deployed manually, move to step 2.

  1. Get project to your PC:

    heroku git:clone -a {your app name}
  2. Init upstream repo (this repository or its fork)

    git remote add origin https://github.com/khoben/telemirror
  3. Get latest changes

    git pull origin master
  4. Push latest changes to heroku

    git push heroku master -f

Locally:

  1. Create and activate python virtual environment

    python -m venv venv
    source ./venv/Scripts/activate # linux
    venv/Scripts/activate # windows
  2. Install dependencies

    pip install -r requirements.txt
  3. Run

    python main.py

telemirror's People

Contributors

khoben avatar mashed-potatoes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

telemirror's Issues

Error deleting a message

telemirror_1  | Traceback (most recent call last):
telemirror_1  |   File "/app/telemirror/mirroring.py", line 196, in on_edit_message
telemirror_1  |     await self.edit_message(
telemirror_1  |   File "/usr/local/lib/python3.11/site-packages/telethon/client/messages.py", line 1212, in edit_message
telemirror_1  |     msg = self._get_response_message(request, await self(request), entity)
telemirror_1  |                                               ^^^^^^^^^^^^^^^^^^^
telemirror_1  |   File "/usr/local/lib/python3.11/site-packages/telethon/client/users.py", line 30, in __call__
telemirror_1  |     return await self._call(self._sender, request, ordered=ordered)
telemirror_1  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
telemirror_1  |   File "/usr/local/lib/python3.11/site-packages/telethon/client/users.py", line 84, in _call
telemirror_1  |     result = await future
telemirror_1  |              ^^^^^^^^^^^^
telemirror_1  | telethon.errors.rpcerrorlist.MessageNotModifiedError: Content of the message was not modified (caused by EditMessageRequest)

При любом удаленном сообщении в логах докера срабатывает traceback, но сообщение всё равно удаляется.

Images from restricted channels

As I've been using telemirror for a while now and came to test all of its features. I can confirm that it pulls content from restricted channels but just not media (images,videos). I just want to confirm if this is a problem from my side or its something that cannot be achieved ?

Facing AttributeError

Hi, I'm currently testing forwards from channel to channel,
Whenever I try to test it by sending a message I get this error

`INFO:main:Channel mirroring has started with config:
Mirror mapping:
-1001748000891 -> -1001621765064
Message deleting: Enabled
Message editing: Enabled
Installed message filter: ForwardFormatFilter
Using database: InMemoryDatabase

ERROR:telethon.client.updates:Unhandled exception on on_new_message
Traceback (most recent call last):
File "/home/xyz/.local/lib/python3.9/site-packages/telethon/client/updates.py", line 454, in _dispatch_update
await callback(event)
File "/home/xyz/Desktop/telemirror/telemirror/mirroring.py", line 24, in on_new_message
if event.message.chat.noforwards:
AttributeError: 'Channel' object has no attribute 'noforwards'`

Фильтр сообщений с каналов

Привет. Спасибо еще раз з программу. Сейчас собираю сообщения с чатов, возникла необходимость отсеивать (не пересылать) репосты с публичных каналов. Каким образом это можно сделать? Заранее спасибо за ответ

Error

2022-05-13T09:14:17.906673+00:00 app[run.1]: ValueError: Not a valid string
2022-05-13T09:14:18.067854+00:00 heroku[run.1]: Process exited with status 1
2022-05-13T09:14:18.317335+00:00 heroku[run.1]: State changed from up to crashed
2022-05-13T09:15:03.498661+00:00 heroku[router]: at=error code=H14 desc="No web processes running" method=GET path="/"

Clone Reply

hi,
The idea of mirroring is very good.
I am specially looking for a Clone Reply feature.in the latest version of telemirror,
Suppose the original channel sends a message then receiver gets a new message.
but when original channel reply's to that message, Receiver gets a new message instead of reply to prior message.

is there any option for that??

Error while deployment

Traceback (most recent call last):
File "/usr/local/lib/python3.11/asyncio/tasks.py", line 500, in wait_for
return fut.result()
^^^^^^^^^^^^
File "/app/dependencies/telethon/client/telegrambaseclient.py", line 544, in connect
if not await self._sender.connect(self._connection(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/dependencies/telethon/network/mtprotosender.py", line 132, in connect
await self._connect()
File "/app/dependencies/telethon/network/mtprotosender.py", line 232, in _connect
connected = await self._try_connect(attempt)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/dependencies/telethon/network/mtprotosender.py", line 282, in _try_connect
await self._connection.connect(timeout=self._connect_timeout)
File "/app/dependencies/telethon/network/connection/connection.py", line 244, in connect
await self._connect(timeout=timeout, ssl=ssl)
File "/app/dependencies/telethon/network/connection/connection.py", line 216, in _connect
self._reader, self._writer = await asyncio.wait_for(
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/asyncio/tasks.py", line 476, in wait_for
await waiter
asyncio.exceptions.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/app/telemirror/mirroring.py", line 504, in __connect_client
await asyncio.wait_for(client.connect(), timeout=client._timeout)
File "/usr/local/lib/python3.11/asyncio/tasks.py", line 502, in wait_for
raise exceptions.TimeoutError() from exc

TimeoutError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/app/main.py", line 105, in
main()
File "/app/main.py", line 91, in main
asyncio.run(
File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "uvloop/loop.pyx", line 1517, in uvloop.loop.Loop.run_until_complete
File "/app/main.py", line 66, in run_telemirror
await telemirror.run()
File "/app/telemirror/mirroring.py", line 581, in run
await self._mirroring.run()
File "/app/telemirror/mirroring.py", line 480, in run
await self.__connect_client(self._sender)
File "/app/telemirror/mirroring.py", line 506, in __connect_client
raise RuntimeError(
RuntimeError: Timeout error while connecting to Telegram server, try restart or get a new session key (run login.py)

where to find mirror.config.yml

everything is fine but it seems that i can't find mirror.config.yml where to find it?
and if i have to make it how to exactly?

thanks for your great work and keep up the good work <3

[FEATURE] Replace word - text transformation

I see in past someone ask this feature.
I'm a newbie on python so i'm not skilled to modify your code.

Usefull feature it's to replace some Word , or Phrase with another one.
Real Scenario :

For example i have an Expert Advisort in MT4 that read signal from telegram, using of course a Telegram BOT, so the bot must be the administrator of channel.

I need to mirror original channel on my channel (where i put the bot), and this is working fine and it's amazing.
Original channel it's a signal channel, free or payment and i have no influence on the format or text.

However my expert advisor (of couse i don't have source to modify this one) maybe read only TP and not TakeProfit, so when i copy to my channel i need to transform .
In the original Message he write "TakeProfit" i need to transform in "TP", or maybe write "trail stop loss to be" i need to transform to "Set SL"

SkipWithKeywordsFilter

Подскажите, SkipWithKeywordsFilter привязан к регистру? "подпишитесь" и "ПОДПИШИТЕСЬ" - одно и то же слово для исключения?

Could Not forward replied messages

Hi, Thanks for creating repo.
I have one problem while using this, whenever there is a replied message which was not cached earlier I mean when any older message is replied which was send before running the bot. It can't forward that message.
It throws this error

`2022-09-20T04:15:35.939775+00:00 app[run.1]: ERROR:main:'NoneType' object is not iterable

2022-09-20T04:15:35.939777+00:00 app[run.1]: Traceback (most recent call last):

2022-09-20T04:15:35.939778+00:00 app[run.1]: File "/app/telemirror/mirroring.py", line 45, in on_new_message

2022-09-20T04:15:35.939778+00:00 app[run.1]: reply_to_messages: dict[int, int] = {

2022-09-20T04:15:35.939778+00:00 app[run.1]: TypeError: 'NoneType' object is not iterable`

Any solution for this?

Фильтрация дубликатов сообщений

Было бы здорово иметь фильтр проверки на оригинальность последних 10-50 сообщений. Очень часто многие каналы пересылают свои посты между собой, в следствие чего происходит их дублирование. У сообщения есть уникальный id, который сохраняется при пересылке?
Если нет, то возможно хотя бы фильтровать текст этих сообщений, по начальным словам.

Problem with mirror.config.yml

ru.
В примере указана переменная targets, которая по идее не должна быть обязательна.
При её удалении в цикле обработки конфига возникает ошибка.
eng.
The example specifies the variable targets, which in theory should not be required.
When it is deleted, an error occurs in the config processing cycle.

make find & replace filter for exceptions & must have/not value found for mirror permission

hi khoben ,
please make filter & replace for exceptions for multiple words.for exam if find value-a in post descriptions can replace with custom one & can set multi env value for multiple values replacement.
for expert mode if you can set ( must have word/must not have ) mode for can be repost in destination channel , it's so much useful.
it means in must have mode , must in post description find value1 & if can't find bypass that post for repost & vice versa for must not have mode.
waiting for your changes commits :)
finest regards
goodbye

Пропуски при копировании.

Привет, спасибо еще раз за программу. Столкнулся, что программа может рандрмно пропускать посты при копировании в каналы. В чем может быть дело, куда копать? Крутиться в докере на виртуалке. Оперативной памяти и мощности проца судя по графикам хватает. Спасибо

Not Forwarding Specific channel

is there any reason that a specific channel is not being mirrored?

 - from: [-1001479163323]
    to: [] # my channel id
    disable_delete: true
    filters:
      - ForwardFormatFilter:
          format: "Forwarded from [{channel_name}]({message_link})\n\n{message_text}"

I have other channels in my config that all seem to be working apart from this one.

it also doesn't receive the "New message" log in the log file when a message is receive on the channel

the bot is obviously a member of both channels

how to forward previous messages

It's works fine for forwarding of new messages. But how to forward previous messages.
I want to forward all messages in a channel to another channel

SkipWithKeywordsFilter

How currently this feature writes in config?
Also, maybe create fully exampled referenced configuration?

Не получается запустить

Так и не получилось запустить код, если не сложно сделай инструкцию для чайников. Через 9 дней удаляют мой любимый канал по причине неактива его автора. Нужно срочно его отзеркалить.

[Help] To filter forwarded messages

Привет, спасибо за программу, она супер. Переписал, чтобы пересылались сообщения с заданными словами (вместо пропуска). Никак не могу сделать не точный поиск по словам. Как изменить код, чтобы поиск осуществлялся по неточному совпадению, например, искало все слова, в которых встречается "дом" (домик, домкрат и тп). И можно ли через одну строку задать неточный поиск по нескольким ключивым словам?

Еще видел, что в предыдущих релизах у тебя фильтр прикручивался к конкретному каналу. Можно ли вернуть данную опцию? А то для нескольких каналов с разными ключевыми словами надо будет запускать несколько версий программы.

Спасибо

Бан аккаунта про login.py

Просрочилась сесссия, сделал вновь login.py и получил моментальный бан. Завёл новый аккаунт - также бан. Политика телеграма изменилась?

Forward to topic

Is it possible to forward a message to channel topic with this bot? Usual channel ID is: -100?????, channel topic ID is: -100?????_111111

[HELP] Skip restricted content

HI,
thank's for your work,
I enable the forward of restrict channel.
i uncommented this

Skip 'restricted saving content' enabled
on event on_new_message

there is a way for this channel mirror only the text , maybe the image (saving to array) ?
(i see one old post)

I can skip all the other element , audio, album etc.. ?
In few word i'm try to avoid the ban, and i'm interested on only text part and maybe images of every message.

Thank's

Delay for forwards

Hello,
thank you for the tool, it's great and works very well. The only problem I have is that i sometimes have a delay from 10-30 seconds. Sometimes its only 1 second what is fine because for my use case, I need as minimal delay as possible. Are there ways to reduce the delay, could it be due to the code or is it related to the Telegram API or the source channels?
I tried different settings and have a minumum config (only in .env file - i dont use the filter file):
Thats how my .env file looks:
API_ID=123
API_HASH=123
SESSION_STRING=123
USE_MEMORY_DB=true
CHAT_MAPPING=[-10012345678:-10012345678910];
YAML_CONFIG_ENV=\ndisable_edit: true\ndisable_delete: true\nmode: forward\n\n# (Required) Mirror directions\ndirections:\n - from: [-10012345678:]\n to: [-10012345678910]\n\n

The new message in the source channel gets recognized sometimes with a lot of delay, i watched it live now and the tg timestamp of the source channel was: 20:55:13
Then nothing happened a long time and then the messagee showed up in cli:
INFO 2024-02-26 19:56:02,874 [mirroring.py:69]:telemirror: [New message]: https://t.me/c/123254346/25352

And then the message got delivered in my channel with the timestamp 20:56:04.
Do you have any idea to improve that?

Best regards

[Feature] replace a word

a function to change specific words, example, in the message I forwarded had the word "flowers" and I want to change this word "flowers" to "hello

example to SkipWithKeywordsFilter

where i put keywords ?

class SkipWithKeywordsFilter(MessageFilter):
    """Skips message if some keyword found
    """
    def __init__(self, keywords: set[str]) -> None:
        self._regex = re.compile(
            '|'.join([f'\\b{k}\\b' for k in keywords]), flags=re.IGNORECASE)

    async def process(self, message: EventMessage) -> Tuple[bool, EventMessage]:
        if self._regex.search(message.message):
            return False, message
        return True, message

string session

how to get string session?
im not understand after try manytimes

stops forwarding from the news channel

So there is a news channel channel1 from where I configured forwarding to my test2 channel and added some filters, I first checked on my two channels test1 > test2 forwarding works, filters work correctly. Then I configured forwarding from channel1, it forwarded for a while, then it stopped, and I thought that the problem was in the filters, but when I copied from the channel1 to my test1 channel from where I also configured forwarding to test2, they were forwarded.
In other words, something is going on, the work is not stable. One and the same text from channel1 is not forwarded to test2, but from test1 to test2 is forwarded.
Maybe you can modify the script a little bit, so that it would be possible to use userbot user account in addition to bot.
chatgpt said
The bot can read messages, but with the limitations of Telegram's API for regular users.
Messages may be delayed or skipped due to frequency restrictions on requests.
Possible solutions:
Using a user account:
A user account (userbot) can be used instead of a bot.
This will allow you to subscribe to the channel and read messages, but may violate Telegram's terms of use.

Пара вопросов по функционалу

Здравствуйте. Хотел бы попробовать вашу библиотеку для пересылки сообщений из своего закрытого канала в публичный. На основе этого у меня есть пара вопросов:

  1. Есть ли в планах ввести настройку задержки между публикациями сообщений?
  2. Реализованы ли у вас какие-нибудь механизмы уменьшения риска бана? Я пробовал несколько других библиотек и через определенное время номер улетал в бан. Хоть номер и восстанавливали, но часто испытывать поддержку тг не хочется. Номер участвовавший в тесте старый, плотность сообщений в группе не высокая, но иногда интервал между сообщениями может быть меньше 2-3 минут.

Exception when message received

Anyone got any thoughts on why this maybe?

Traceback (most recent call last):
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python312\Lib\site-packages\aiohttp\web_protocol.py", line
350, in data_received
    messages, upgraded, tail = self._request_parser.feed_data(data)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "aiohttp\\_http_parser.pyx", line 557, in aiohttp._http_parser.HttpParser.feed_data
aiohttp.http_exceptions.BadStatusLine: 400, message:
  Invalid method encountered:

    b'\x16\x03\x01'
      ^
Error handling request
Traceback (most recent call last):
  File "C:\Users\Administrator\AppData\Local\Programs\Python\Python312\Lib\site-packages\aiohttp\web_protocol.py", line
350, in data_received
    messages, upgraded, tail = self._request_parser.feed_data(data)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "aiohttp\\_http_parser.pyx", line 557, in aiohttp._http_parser.HttpParser.feed_data
aiohttp.http_exceptions.BadStatusLine: 400, message:
  Invalid method encountered:

    b'nil'
      ^

Offering new bot features.

Было бы здорово реализовать gui добавление/удаление каналов из конфига. В качестве места обработки команд можно использовать сообщения с самим собой. В совершенстве это может быть реализовано с помощью бота, в котором было бы инлайн меню и который был бы связан с юзерботом. Также жду предложенной ранее функции фильтрации повторных сообщений. Готов внести пожертвование ради таких "премиум" функций

Docker Porting

Any way to use this great utility on docker?
I am planning to use it on my synology nas Docker.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.