diff --git a/CHANGELOG.md b/CHANGELOG.md index f36a470..4865197 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Change log +## Version 0.7.2 (2022/08/27) + +#### Bugs Fixed + +* [Issue 32](https://github.com/SamR1/python-twootfeed/issues/32) - GIFs not showing + +In this release 1 issue was closed. + + ## Version 0.7.1 (2022/07/16) #### Misc @@ -34,7 +43,7 @@ Note: **twootfeed** still using **Twitter** API v1.1 * [Issue 27](https://github.com/SamR1/python-twootfeed/issues/27) - generate documentation with sphinx * [Issue 26](https://github.com/SamR1/python-twootfeed/issues/26) - [Mastodon] add feed with user's bookmarks -In this release 2 issue were closed. +In this release 2 issues were closed. ## Version 0.6.6 (2019/10/20) diff --git a/Makefile b/Makefile index 281989a..dd8fb6a 100644 --- a/Makefile +++ b/Makefile @@ -41,8 +41,8 @@ serve: $(FLASK) run --with-threads -h $(HOST) -p $(PORT) run: - echo 'Running on http://$(HOST):$(PORT)' - FLASK_ENV=production && $(GUNICORN) -b 127.0.0.1:5000 "$(FLASK_APP):create_app()" --error-logfile $(GUNICORN_LOG) + echo 'Running on http://localhost:$(PORT)' + FLASK_ENV=production && $(GUNICORN) -b 127.0.0.1:$(PORT) "$(FLASK_APP):create_app()" --error-logfile $(GUNICORN_LOG) venv: test -d $(VENV) || $(PYTHON_VERSION) -m venv $(VENV) diff --git a/Makefile.config b/Makefile.config index c97c941..2bcc50b 100644 --- a/Makefile.config +++ b/Makefile.config @@ -3,7 +3,7 @@ PORT = 5000 APP_PATH = $(PWD)/twootfeed export FLASK_APP = twootfeed -export FLASK_ENV=development +export FLASK_DEBUG=1 export TWOOTFEED_CONFIG_DIR=$(APP_PATH)/ export TWOOTFEED_CONFIG_FILE=$(APP_PATH)/config.yml export TWOOTFEED_LOG=twootfeed.log diff --git a/README.md b/README.md index 95d432d..9711f3f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![PyPI version](https://img.shields.io/pypi/v/twootfeed.svg)](https://pypi.org/project/twootfeed/) [![Downloads](https://pepy.tech/badge/twootfeed)](https://pepy.tech/project/twootfeed) [![Python Version](https://img.shields.io/badge/python-3.7+-brightgreen.svg)](https://python.org) -[![Flask Version](https://img.shields.io/badge/flask-2.1-brightgreen.svg)](http://flask.pocoo.org/) +[![Flask Version](https://img.shields.io/badge/flask-2.2-brightgreen.svg)](http://flask.pocoo.org/) [![code style: black](https://img.shields.io/badge/code%20style-black-black)](https://black.readthedocs.io/en/stable/) [![type check: mypy](https://img.shields.io/badge/type%20check-mypy-blue)](http://mypy-lang.org/) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/14d1c00121c04cd2b81453c597639ca6)](https://www.codacy.com/app/SamR1/python-twootfeed) diff --git a/VERSION b/VERSION index 39e898a..7486fdb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.7.1 +0.7.2 diff --git a/docs/.buildinfo b/docs/.buildinfo index b5a36c8..b7f09e9 100644 --- a/docs/.buildinfo +++ b/docs/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: a60a5b8ce7a38d3ffa6039003e56360f +config: 7075c05ace5d0aeb460624acaa55bf96 tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_sources/changelog.md.txt b/docs/_sources/changelog.md.txt index f36a470..4865197 100644 --- a/docs/_sources/changelog.md.txt +++ b/docs/_sources/changelog.md.txt @@ -1,5 +1,14 @@ # Change log +## Version 0.7.2 (2022/08/27) + +#### Bugs Fixed + +* [Issue 32](https://github.com/SamR1/python-twootfeed/issues/32) - GIFs not showing + +In this release 1 issue was closed. + + ## Version 0.7.1 (2022/07/16) #### Misc @@ -34,7 +43,7 @@ Note: **twootfeed** still using **Twitter** API v1.1 * [Issue 27](https://github.com/SamR1/python-twootfeed/issues/27) - generate documentation with sphinx * [Issue 26](https://github.com/SamR1/python-twootfeed/issues/26) - [Mastodon] add feed with user's bookmarks -In this release 2 issue were closed. +In this release 2 issues were closed. ## Version 0.6.6 (2019/10/20) diff --git a/docs/_sources/features.rst.txt b/docs/_sources/features.rst.txt index 5e9be1a..572dd8d 100644 --- a/docs/_sources/features.rst.txt +++ b/docs/_sources/features.rst.txt @@ -4,7 +4,7 @@ Features Description ~~~~~~~~~~~ -**twootfeed** generate an RSS feed from **Twitter** or **Mastodon** search and from **Mastodon** bookmarks/favorites/home timeline. +**twootfeed** generates an RSS feed from **Twitter** or **Mastodon** search and from **Mastodon** bookmarks/favorites/home timeline. The feed displays only the original tweets (not the retweets) and toots, with: @@ -15,8 +15,9 @@ The feed displays only the original tweets (not the retweets) and toots, with: - usernames - URLs -- images -- source +- images, video (mp4) and animated gif (as mp4 video) +- image description (only for Mastodon) +- source if available - location (only for Twitter) - visibility (only for Mastodon) - numbers of retweets and likes for tweets and boosts and favourites for toots diff --git a/docs/_sources/how-to-developers.rst.txt b/docs/_sources/how-to-developers.rst.txt index f1571c4..bba0f82 100644 --- a/docs/_sources/how-to-developers.rst.txt +++ b/docs/_sources/how-to-developers.rst.txt @@ -6,7 +6,7 @@ Dependencies - `Flask `_ - `Feedgenerator `_ -- `Tweepy `_ (only tested with the `Twitter Standard API `_) +- `Tweepy `_ (only tested with the `Twitter Standard v1.1 API `_) - `Mastodon.py `_ - `pytz `_ - `pyYAML `_ diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt index e097232..d3aa8db 100644 --- a/docs/_sources/index.rst.txt +++ b/docs/_sources/index.rst.txt @@ -6,7 +6,7 @@ Welcome to twootfeed's documentation! ===================================== -**twootfeed** generate an rss feed from parsed Twitter or Mastodon search and from Mastodon bookmarks, favorites and home timeline. +**twootfeed** generates an RSS feed from parsed Twitter or Mastodon search and from Mastodon bookmarks, favorites and home timeline. .. toctree:: :maxdepth: 1 diff --git a/docs/_sources/installation.rst.txt b/docs/_sources/installation.rst.txt index d76629a..c9e41bc 100644 --- a/docs/_sources/installation.rst.txt +++ b/docs/_sources/installation.rst.txt @@ -13,18 +13,23 @@ Installation - Create and activate a virtualenv +.. code-block:: bash + + $ python -m venv .venv + $ source .venv/bin/activate + - Install from pip .. code-block:: bash - $ pip install twootfeed + (.venv) $ pip install twootfeed - Initialize the configuration file .. code-block:: bash - $ twootfeed_init + (.venv) $ twootfeed_init - Fill in fields for the client(s) you want to use in **'~/.config/twootfeed/config.yml'** : @@ -82,7 +87,7 @@ After generation, copy the value into **'config.yml'**. .. warning:: | If the token is missing or invalid, **twootfeed** will not start. -- The files location and settings can be changed with the following environment variables: +- The files location and settings can be changed by exporting the following environment variables: =========================== =============================================== =========================================================================================== variable description app default value @@ -97,7 +102,7 @@ After generation, copy the value into **'config.yml'**. .. code-block:: bash - $ twootfeed + (.venv) $ twootfeed Upgrade @@ -105,11 +110,15 @@ Upgrade - Activate the virtualenv +.. code-block:: bash + + $ source .venv/bin/activate + - Upgrade with pip .. code-block:: bash - $ pip install -U twootfeed + (.venv) $ pip install -U twootfeed - Restart the application diff --git a/docs/_static/basic.css b/docs/_static/basic.css index 7d5974c..eeb0519 100644 --- a/docs/_static/basic.css +++ b/docs/_static/basic.css @@ -608,8 +608,6 @@ ol.simple p, ul.simple p { margin-bottom: 0; } - -/* Docutils 0.17 and older (footnotes & citations) */ dl.footnote > dt, dl.citation > dt { float: left; @@ -627,33 +625,6 @@ dl.citation > dd:after { clear: both; } -/* Docutils 0.18+ (footnotes & citations) */ -aside.footnote > span, -div.citation > span { - float: left; -} -aside.footnote > span:last-of-type, -div.citation > span:last-of-type { - padding-right: 0.5em; -} -aside.footnote > p { - margin-left: 2em; -} -div.citation > p { - margin-left: 4em; -} -aside.footnote > p:last-of-type, -div.citation > p:last-of-type { - margin-bottom: 0em; -} -aside.footnote > p:last-of-type:after, -div.citation > p:last-of-type:after { - content: ""; - clear: both; -} - -/* Footnotes & citations ends */ - dl.field-list { display: grid; grid-template-columns: fit-content(30%) auto; @@ -665,11 +636,11 @@ dl.field-list > dt { padding-left: 0.5em; padding-right: 5px; } - dl.field-list > dt:after { content: ":"; } + dl.field-list > dd { padding-left: 0.5em; margin-top: 0em; diff --git a/docs/_static/documentation_options.js b/docs/_static/documentation_options.js index 794adb8..82c7ee5 100644 --- a/docs/_static/documentation_options.js +++ b/docs/_static/documentation_options.js @@ -1,6 +1,6 @@ var DOCUMENTATION_OPTIONS = { URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '0.7.1', + VERSION: '0.7.2', LANGUAGE: 'en', COLLAPSE_INDEX: false, BUILDER: 'html', @@ -10,5 +10,5 @@ var DOCUMENTATION_OPTIONS = { SOURCELINK_SUFFIX: '.txt', NAVIGATION_WITH_KEYS: false, SHOW_SEARCH_SUMMARY: true, - ENABLE_SEARCH_SHORTCUTS: false, + ENABLE_SEARCH_SHORTCUTS: true, }; \ No newline at end of file diff --git a/docs/_static/searchtools.js b/docs/_static/searchtools.js index ac4d586..f2fb7d5 100644 --- a/docs/_static/searchtools.js +++ b/docs/_static/searchtools.js @@ -88,7 +88,7 @@ const _displayItem = (item, highlightTerms, searchTerms) => { linkEl.href = linkUrl + "?" + params.toString() + anchor; linkEl.innerHTML = title; if (descr) - listItem.appendChild(document.createElement("span")).innerText = + listItem.appendChild(document.createElement("span")).innerHTML = " (" + descr + ")"; else if (showSearchSummary) fetch(requestUrl) @@ -155,10 +155,8 @@ const Search = { _pulse_status: -1, htmlToText: (htmlString) => { - const htmlElement = document - .createRange() - .createContextualFragment(htmlString); - _removeChildren(htmlElement.querySelectorAll(".headerlink")); + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); const docContent = htmlElement.querySelector('[role="main"]'); if (docContent !== undefined) return docContent.textContent; console.warn( @@ -504,11 +502,12 @@ const Search = { * latter for highlighting it. */ makeSearchSummary: (htmlText, keywords, highlightWords) => { - const text = Search.htmlToText(htmlText).toLowerCase(); + const text = Search.htmlToText(htmlText); if (text === "") return null; + const textLower = text.toLowerCase(); const actualStartPosition = [...keywords] - .map((k) => text.indexOf(k.toLowerCase())) + .map((k) => textLower.indexOf(k.toLowerCase())) .filter((i) => i > -1) .slice(-1)[0]; const startWithContext = Math.max(actualStartPosition - 120, 0); @@ -516,9 +515,9 @@ const Search = { const top = startWithContext === 0 ? "" : "..."; const tail = startWithContext + 240 < text.length ? "..." : ""; - let summary = document.createElement("div"); + let summary = document.createElement("p"); summary.classList.add("context"); - summary.innerText = top + text.substr(startWithContext, 240).trim() + tail; + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; highlightWords.forEach((highlightWord) => _highlightText(summary, highlightWord, "highlighted") diff --git a/docs/changelog.html b/docs/changelog.html index d5f9cb9..828bc20 100644 --- a/docs/changelog.html +++ b/docs/changelog.html @@ -4,7 +4,7 @@ - Change log — twootfeed 0.7.1 + <title>Change log — twootfeed 0.7.2 documentation @@ -32,7 +32,7 @@ twootfeed
- 0.7.1 + 0.7.2
@@ -50,6 +50,10 @@
  • Application and feeds parameters
  • Quick start for developers
  • Change log
  • Version 0.6.5 (2019/09/23)
  • Version 0.6.4 (2019/08/31)
  • Version 0.6.3 (2019/05/05)
  • Version 0.6.2 (2019/01/26)
  • Version 0.6.1 (2019/01/25)
  • Version 0.6.0 (2019/01/23)
  • Version 0.5.1 (2018-10-17)
  • Version 0.5.0 - Mastodon extended support (2018-10-14)
  • Version 0.4.0 - make support (2018-04-01)
  • Version 0.3.0 - Mastodon favorites support (2017-12-07)
  • Version 0.2.1 (2017-05-03)
  • Version 0.2.0 (2017-04-18)
  • Version 0.1.0 (2017-04-18)
  • @@ -160,6 +164,16 @@

    Change log

    +
    +

    Version 0.7.2 (2022/08/27)

    +
    +

    Bugs Fixed

    + +

    In this release 1 issue was closed.

    +
    +

    Version 0.7.1 (2022/07/16)

    @@ -204,7 +218,7 @@

    New FeaturesIssue 27 - generate documentation with sphinx

  • Issue 26 - [Mastodon] add feed with user’s bookmarks

  • -

    In this release 2 issue were closed.

    +

    In this release 2 issues were closed.

    @@ -218,8 +232,8 @@

    Misc<

    Version 0.6.5 (2019/09/23)

    -
    -

    Bugs Fixed

    +
    +

    Bugs Fixed

    • Issue 25 - toot_search route returns 404 error

    @@ -228,8 +242,8 @@

    Bugs Fixed

    Version 0.6.4 (2019/08/31)

    -
    -

    Misc

    +
    +

    Misc

    • Update dependencies

    @@ -237,14 +251,14 @@

    Misc<

    Version 0.6.3 (2019/05/05)

    -
    -

    Bugs Fixed

    +
    +

    Bugs Fixed

    • Issue 24 - return the correct HTTP code status when no keys are provided

    -
    -

    Misc

    +
    +

    Misc

    • Update dependencies

    @@ -253,8 +267,8 @@

    Misc<

    Version 0.6.2 (2019/01/26)

    -
    -

    New Features

    +
    +

    New Features

    Built with Sphinx using a diff --git a/docs/features.html b/docs/features.html index 2006acd..03dc86e 100644 --- a/docs/features.html +++ b/docs/features.html @@ -4,7 +4,7 @@ - Features — twootfeed 0.7.1 + <title>Features — twootfeed 0.7.2 documentation @@ -33,7 +33,7 @@ twootfeed
    - 0.7.1 + 0.7.2
    @@ -84,7 +84,7 @@

    Features

    Description

    -

    twootfeed generate an RSS feed from Twitter or Mastodon search and from Mastodon bookmarks/favorites/home timeline.

    +

    twootfeed generates an RSS feed from Twitter or Mastodon search and from Mastodon bookmarks/favorites/home timeline.

    The feed displays only the original tweets (not the retweets) and toots, with:

    Built with Sphinx using a diff --git a/docs/genindex.html b/docs/genindex.html index 58111ac..739e905 100644 --- a/docs/genindex.html +++ b/docs/genindex.html @@ -3,7 +3,7 @@ - Index — twootfeed 0.7.1 + <title>Index — twootfeed 0.7.2 documentation @@ -30,7 +30,7 @@ twootfeed
    - 0.7.1 + 0.7.2
    @@ -88,7 +88,7 @@

    Index


    -

    © Copyright 2015 - 2021, SamR1.

    +

    © Copyright 2015 - 2022, SamR1.

    Built with Sphinx using a diff --git a/docs/how-to-developers.html b/docs/how-to-developers.html index 24154d8..a2202e1 100644 --- a/docs/how-to-developers.html +++ b/docs/how-to-developers.html @@ -4,7 +4,7 @@ - Quick start for developers — twootfeed 0.7.1 + <title>Quick start for developers — twootfeed 0.7.2 documentation @@ -33,7 +33,7 @@ twootfeed
    - 0.7.1 + 0.7.2
    @@ -89,7 +89,7 @@

    Dependencies
  • Flask

  • Feedgenerator

  • -
  • Tweepy (only tested with the Twitter Standard API)

  • +
  • Tweepy (only tested with the Twitter Standard v1.1 API)

  • Mastodon.py

  • pytz

  • pyYAML

  • @@ -141,7 +141,7 @@

    Tests
    -

    © Copyright 2015 - 2021, SamR1.

    +

    © Copyright 2015 - 2022, SamR1.

    Built with
    Sphinx using a diff --git a/docs/index.html b/docs/index.html index dcefd10..abf089f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -4,7 +4,7 @@ - Welcome to twootfeed’s documentation! — twootfeed 0.7.1 + <title>Welcome to twootfeed’s documentation! — twootfeed 0.7.2 documentation @@ -32,7 +32,7 @@ twootfeed
    - 0.7.1 + 0.7.2
    @@ -78,7 +78,7 @@

    Welcome to twootfeed’s documentation!

    -

    twootfeed generate an rss feed from parsed Twitter or Mastodon search and from Mastodon bookmarks, favorites and home timeline.

    +

    twootfeed generates an RSS feed from parsed Twitter or Mastodon search and from Mastodon bookmarks, favorites and home timeline.

    Contents

    Built with Sphinx using a diff --git a/docs/installation.html b/docs/installation.html index c4de884..9ead031 100644 --- a/docs/installation.html +++ b/docs/installation.html @@ -4,7 +4,7 @@ - Installation and usage — twootfeed 0.7.1 + <title>Installation and usage — twootfeed 0.7.2 documentation @@ -33,7 +33,7 @@ twootfeed
    - 0.7.1 + 0.7.2
    @@ -97,15 +97,21 @@

    Requirements

    • Create and activate a virtualenv

    • +
    +
    $ python -m venv .venv
    +$ source .venv/bin/activate
    +
    +
    +
    • Install from pip

    -
    $ pip install twootfeed
    +
    (.venv) $ pip install twootfeed
     
    • Initialize the configuration file

    -
    $ twootfeed_init
    +
    (.venv) $ twootfeed_init
     
    @@ -203,7 +209,7 @@

    Installation
  • Start the app

  • -
    $ twootfeed
    +
    (.venv) $ twootfeed
     
    @@ -211,9 +217,14 @@

    Installation

    • Activate the virtualenv

    • +
    +
    $ source .venv/bin/activate
    +
    +
    +
    • Upgrade with pip

    -
    $ pip install -U twootfeed
    +
    (.venv) $ pip install -U twootfeed
     
      @@ -334,7 +345,7 @@

      Usage
      -

      © Copyright 2015 - 2021, SamR1.

      +

      © Copyright 2015 - 2022, SamR1.

      Built with
      Sphinx using a diff --git a/docs/objects.inv b/docs/objects.inv index 3cd2d0e..c993a29 100644 --- a/docs/objects.inv +++ b/docs/objects.inv @@ -1,6 +1,6 @@ # Sphinx inventory version 2 # Project: twootfeed -# Version: 0.7.1 +# Version: 0.7.2 # The remainder of this file is compressed using zlib. xڅMN0 99@زC#!@ĂIQ03;8 iӪ- ^ݣrI̭a EY8L#Y#-h'ՑZ|%;‹ZS|jC3PܥZVS[0 aݫuAN͎ JFvQ! ;RׇK,M4Cj܅`' 6%/җO$¨j\o* \ No newline at end of file diff --git a/docs/parameters.html b/docs/parameters.html index 144ffce..95d1d0a 100644 --- a/docs/parameters.html +++ b/docs/parameters.html @@ -4,7 +4,7 @@ - Application and feeds parameters — twootfeed 0.7.1 + <title>Application and feeds parameters — twootfeed 0.7.2 documentation @@ -33,7 +33,7 @@ twootfeed
      - 0.7.1 + 0.7.2
      @@ -164,7 +164,7 @@

      App
      -

      © Copyright 2015 - 2021, SamR1.

      +

      © Copyright 2015 - 2022, SamR1.

      Built with
      Sphinx using a diff --git a/docs/search.html b/docs/search.html index 57bcbbe..c02b44d 100644 --- a/docs/search.html +++ b/docs/search.html @@ -3,7 +3,7 @@ - Search — twootfeed 0.7.1 + <title>Search — twootfeed 0.7.2 documentation @@ -33,7 +33,7 @@ twootfeed
      - 0.7.1 + 0.7.2
      @@ -96,7 +96,7 @@
      -

      © Copyright 2015 - 2021, SamR1.

      +

      © Copyright 2015 - 2022, SamR1.

      Built with Sphinx using a diff --git a/docs/searchindex.js b/docs/searchindex.js index e41192b..e3fa315 100644 --- a/docs/searchindex.js +++ b/docs/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["changelog", "features", "how-to-developers", "index", "installation", "parameters"], "filenames": ["changelog.md", "features.rst", "how-to-developers.rst", "index.rst", "installation.rst", "parameters.rst"], "titles": ["Change log", "Features", "Quick start for developers", "Welcome to twootfeed\u2019s documentation!", "Installation and usage", "Application and feeds parameters"], "terms": {"pr": 0, "minor": 0, "improv": 0, "29": 0, "add": 0, "token": [0, 2, 4, 5], "access": [0, 2, 4, 5], "feed": [0, 1, 2, 3, 4], "break": 0, "28": 0, "home": [0, 1, 3, 4], "timelin": [0, 1, 3, 4], "30": 0, "url": [0, 1, 5], "updat": [0, 4], "depend": [0, 4], "includ": [0, 4], "tweepi": [0, 2], "note": 0, "twootfe": [0, 1, 2, 4, 5], "still": 0, "us": [0, 1, 2, 4, 5], "twitter": [0, 1, 2, 3, 4], "api": [0, 1, 2, 4], "v1": 0, "issu": 0, "27": 0, "gener": [0, 1, 2, 3, 4, 5], "document": 0, "sphinx": 0, "user": [0, 1, 4], "s": [0, 2, 4], "bookmark": [0, 1, 3, 4], "In": 0, "thi": [0, 2], "releas": 0, "were": 0, "close": 0, "toot": [0, 1, 4], "_": 0, "search": [0, 1, 3, 4, 5], "rout": 0, "return": 0, "404": 0, "error": 0, "wa": 0, "24": 0, "correct": 0, "http": [0, 2, 4, 5], "code": 0, "statu": 0, "when": 0, "kei": [0, 1, 2, 4, 5], "ar": [0, 1, 4, 5], "provid": 0, "22": 0, "The": [0, 1, 4], "number": [0, 1, 5], "worker": [0, 5], "server": [0, 2, 5], "can": [0, 4], "set": [0, 4], "21": 0, "pagin": 0, "get": [0, 2, 5], "19": 0, "environ": [0, 4], "variabl": [0, 4], "limit": [0, 4], "item": [0, 1, 4, 5], "avoid": 0, "time": 0, "out": 0, "refer": 0, "charact": [0, 4, 5], "titl": [0, 5], "now": [0, 4], "avail": [0, 4], "pypi": 0, "name": [0, 5], "displai": [0, 1, 4, 5], "usernam": [0, 1], "python": [0, 2, 4], "sinc": [0, 4], "refactor": 0, "continu": 0, "integr": 0, "test": 0, "coverag": 0, "perform": 0, "gunicorn": [0, 2, 5], "product": 0, "long": 0, "tweet": [0, 1, 4], "truncat": 0, "imag": [0, 1], "longer": 0, "handl": 0, "tweeperror": 0, "rate": 0, "exceed": 0, "major": 0, "ad": 0, "makefil": 0, "eas": 0, "instal": [0, 3], "start": [0, 3, 4], "see": [0, 2, 4, 5], "readm": 0, "thank": 0, "georgedorn": 0, "client": [0, 2, 4], "script": [0, 4, 5], "rss": [0, 1, 3, 4], "authent": [0, 4, 5], "regist": [0, 4, 5], "app": [0, 4], "credenti": [0, 4, 5], "flask": [0, 2], "instead": 0, "django": 0, "queri": [0, 4], "descript": [0, 4, 5], "extern": 0, "all": 0, "media": 0, "an": [1, 3, 5], "from": [1, 3, 4, 5], "mastodon": [1, 2, 3, 4], "favorit": [1, 3, 4], "onli": [1, 2], "origin": 1, "retweet": 1, "link": [1, 5], "hashtag": [1, 4], "sourc": 1, "locat": [1, 4], "visibl": [1, 4], "like": [1, 4], "boost": 1, "favourit": 1, "intend": 1, "person": [1, 4], "account": [1, 4], "associ": 1, "mai": [1, 4], "contain": 1, "restrict": [1, 4], "exampl": [1, 4], "freshrss": 1, "feedgener": 2, "standard": 2, "py": 2, "pytz": 2, "pyyaml": 2, "beautifulsoup": 2, "clone": 2, "repo": 2, "git": 2, "github": 2, "com": [2, 4, 5], "samr1": 2, "virtualenv": [2, 4], "packag": 2, "cd": 2, "make": 2, "fill": [2, 4], "field": [2, 4], "you": [2, 4], "config": [2, 4, 5], "yml": [2, 4, 5], "next": 2, "step": 2, "serv": 2, "pars": 3, "featur": 3, "usag": 3, "applic": [3, 4], "paramet": [3, 4], "quick": 3, "develop": [3, 5], "chang": [3, 4], "log": [3, 4], "3": 4, "7": 4, "creat": [4, 5], "activ": 4, "pip": 4, "initi": 4, "configur": 4, "file": [4, 5], "twootfeed_init": 4, "want": 4, "detail": 4, "copi": 4, "past": 4, "valu": 4, "consumerkei": [4, 5], "consumersecret": [4, 5], "wrapper": 4, "which": 4, "your": 4, "prompt": 4, "twootfeed_create_mastodon_cli": 4, "It": 4, "necessari": 4, "temporarili": 4, "disabl": 4, "two": 4, "factor": 4, "enabl": 4, "new": 4, "version": 4, "0": 4, "connect": 4, "privat": 4, "direct": 4, "messag": 4, "A": 4, "mandatori": [4, 5], "expos": 4, "should": 4, "publicli": 4, "some": 4, "minimum": 4, "length": [4, 5], "25": [4, 5], "10": 4, "5": 4, "main": 4, "jun": 4, "6": 4, "2022": 4, "18": 4, "49": 4, "26": 4, "gcc": 4, "12": 4, "1": 4, "linux": 4, "type": 4, "help": 4, "copyright": 4, "credit": 4, "licens": 4, "more": 4, "inform": 4, "import": 4, "secret": 4, "token_urlsaf": 4, "pgoes3qoslhxduzny_gmn6p5vwzqszqbgnb_vpupq7o": 4, "command": 4, "line": 4, "date": 4, "sha256sum": 4, "base64": 4, "head": 4, "c": 4, "echo": 4, "nwu2mze1zgm0mmvlzdg5ndnhn": 4, "after": 4, "If": 4, "miss": 4, "invalid": 4, "follow": 4, "default": 4, "twootfeed_config_dir": 4, "directori": 4, "twootfeed_config_fil": 4, "full": 4, "path": 4, "dir": 4, "twootfeed_log": 4, "print": 4, "consol": 4, "twootfeed_set": 4, "productionconfig": 4, "u": 4, "restart": 4, "To": 4, "sudo": 4, "nano": 4, "etc": 4, "system": 4, "templat": 4, "distribut": 4, "unit": 4, "network": 4, "target": 4, "startlimitintervalsec": 4, "simpl": 4, "alwai": 4, "restartsec": 4, "execstart": 4, "twootfeed_directori": 4, "venv": 4, "bin": 4, "python3": 4, "m": 4, "wantedbi": 4, "multi": 4, "systemctl": 4, "boot": 4, "localhost": [4, 5], "8080": [4, 5], "q": [4, 5], "tag": 4, "without": 4, "lead": 4, "home_timelin": 4, "where": 4, "store": 5, "result": 5, "social": 5, "client_id_fil": 5, "tootrss_clientcr": 5, "txt": 5, "access_token_fil": 5, "tootrss_usercr": 5, "app_nam": 5, "tootrss": 5, "identifi": 5, "languag": 5, "fr": 5, "author_nam": 5, "feed_url": 5, "timezon": 5, "europ": 5, "pari": 5, "text_length_limit": 5, "100": 5, "max_item": 5, "20": 5, "host": 5, "port": 5, "nb_worker": 5, "2": 5, "defin": 5, "en": 5, "instanc": 5, "author": 5, "maximum": 5, "minim": 5, "wsgi": 5, "calcul": 5}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"chang": 0, "log": 0, "version": 0, "0": 0, "7": 0, "1": 0, "2022": 0, "07": 0, "16": 0, "misc": 0, "15": 0, "new": 0, "featur": [0, 1], "6": 0, "8": 0, "2021": 0, "10": 0, "05": 0, "2020": 0, "03": 0, "2019": 0, "20": 0, "5": 0, "09": 0, "23": 0, "bug": 0, "fix": 0, "4": 0, "08": 0, "31": 0, "3": 0, "2": 0, "01": 0, "26": 0, "25": 0, "2018": 0, "17": 0, "mastodon": [0, 5], "extend": 0, "support": 0, "14": 0, "make": 0, "04": 0, "favorit": 0, "2017": 0, "12": 0, "18": 0, "descript": 1, "quick": 2, "start": 2, "develop": 2, "depend": 2, "instal": [2, 4], "test": 2, "welcom": 3, "twootfe": 3, "s": 3, "document": 3, "content": 3, "usag": 4, "requir": 4, "upgrad": 4, "systemd": 4, "servic": 4, "applic": 5, "feed": 5, "paramet": 5, "twitter": 5, "app": 5}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 56}}) \ No newline at end of file +Search.setIndex({"docnames": ["changelog", "features", "how-to-developers", "index", "installation", "parameters"], "filenames": ["changelog.md", "features.rst", "how-to-developers.rst", "index.rst", "installation.rst", "parameters.rst"], "titles": ["Change log", "Features", "Quick start for developers", "Welcome to twootfeed\u2019s documentation!", "Installation and usage", "Application and feeds parameters"], "terms": {"issu": 0, "32": 0, "gif": [0, 1], "show": 0, "In": 0, "thi": [0, 2], "releas": 0, "wa": 0, "close": 0, "pr": 0, "minor": 0, "improv": 0, "29": 0, "add": 0, "token": [0, 2, 4, 5], "access": [0, 2, 4, 5], "feed": [0, 1, 2, 3, 4], "break": 0, "28": 0, "home": [0, 1, 3, 4], "timelin": [0, 1, 3, 4], "30": 0, "url": [0, 1, 5], "updat": [0, 4], "depend": [0, 4], "includ": [0, 4], "tweepi": [0, 2], "note": 0, "twootfe": [0, 1, 2, 4, 5], "still": 0, "us": [0, 1, 2, 4, 5], "twitter": [0, 1, 2, 3, 4], "api": [0, 1, 2, 4], "v1": [0, 2], "gener": [0, 1, 2, 3, 4, 5], "document": 0, "sphinx": 0, "user": [0, 1, 4], "": [0, 2, 4], "bookmark": [0, 1, 3, 4], "were": 0, "toot": [0, 1, 4], "_": 0, "search": [0, 1, 3, 4, 5], "rout": 0, "return": 0, "404": 0, "error": 0, "24": 0, "correct": 0, "http": [0, 2, 4, 5], "code": 0, "statu": 0, "when": 0, "kei": [0, 1, 2, 4, 5], "ar": [0, 1, 4, 5], "provid": 0, "22": 0, "The": [0, 1, 4], "number": [0, 1, 5], "worker": [0, 5], "server": [0, 2, 5], "can": [0, 4], "set": [0, 4], "21": 0, "pagin": 0, "get": [0, 2, 5], "19": 0, "environ": [0, 4], "variabl": [0, 4], "limit": [0, 4], "item": [0, 1, 4, 5], "avoid": 0, "time": 0, "out": 0, "refer": 0, "charact": [0, 4, 5], "titl": [0, 5], "i": [0, 1, 4, 5], "now": [0, 4], "avail": [0, 1, 4], "pypi": 0, "name": [0, 5], "displai": [0, 1, 4, 5], "usernam": [0, 1], "python": [0, 2, 4], "sinc": [0, 4], "refactor": 0, "continu": 0, "integr": 0, "test": 0, "coverag": 0, "perform": 0, "gunicorn": [0, 2, 5], "product": 0, "long": 0, "tweet": [0, 1, 4], "truncat": 0, "imag": [0, 1], "longer": 0, "handl": 0, "tweeperror": 0, "rate": 0, "exceed": 0, "major": 0, "ad": 0, "makefil": 0, "eas": 0, "instal": [0, 3], "start": [0, 3, 4], "see": [0, 2, 4, 5], "readm": 0, "thank": 0, "georgedorn": 0, "client": [0, 2, 4], "script": [0, 4, 5], "rss": [0, 1, 3, 4], "authent": [0, 4, 5], "regist": [0, 4, 5], "app": [0, 4], "credenti": [0, 4, 5], "flask": [0, 2], "instead": 0, "django": 0, "queri": [0, 4], "descript": [0, 4, 5], "extern": 0, "all": 0, "media": 0, "an": [1, 3, 5], "from": [1, 3, 4, 5], "mastodon": [1, 2, 3, 4], "favorit": [1, 3, 4], "onli": [1, 2], "origin": 1, "retweet": 1, "link": [1, 5], "hashtag": [1, 4], "video": 1, "mp4": 1, "anim": 1, "sourc": [1, 4], "locat": [1, 4], "visibl": [1, 4], "like": [1, 4], "boost": 1, "favourit": 1, "intend": 1, "person": [1, 4], "account": [1, 4], "associ": 1, "mai": [1, 4], "contain": 1, "restrict": [1, 4], "exampl": [1, 4], "freshrss": 1, "feedgener": 2, "standard": 2, "1": [2, 4], "py": 2, "pytz": 2, "pyyaml": 2, "beautifulsoup": 2, "clone": 2, "repo": 2, "git": 2, "github": 2, "com": [2, 4, 5], "samr1": 2, "virtualenv": [2, 4], "packag": 2, "cd": 2, "make": 2, "fill": [2, 4], "field": [2, 4], "you": [2, 4], "config": [2, 4, 5], "yml": [2, 4, 5], "next": 2, "step": 2, "serv": 2, "pars": 3, "featur": 3, "usag": 3, "applic": [3, 4], "paramet": [3, 4], "quick": 3, "develop": [3, 5], "chang": [3, 4], "log": [3, 4], "3": 4, "7": 4, "creat": [4, 5], "activ": 4, "m": 4, "venv": 4, "bin": 4, "pip": 4, "initi": 4, "configur": 4, "file": [4, 5], "twootfeed_init": 4, "want": 4, "detail": 4, "copi": 4, "past": 4, "valu": 4, "consumerkei": [4, 5], "consumersecret": [4, 5], "wrapper": 4, "which": 4, "your": 4, "prompt": 4, "twootfeed_create_mastodon_cli": 4, "It": 4, "necessari": 4, "temporarili": 4, "disabl": 4, "two": 4, "factor": 4, "enabl": 4, "new": 4, "version": 4, "0": 4, "connect": 4, "privat": 4, "direct": 4, "messag": 4, "A": 4, "mandatori": [4, 5], "expos": 4, "should": 4, "publicli": 4, "some": 4, "minimum": 4, "length": [4, 5], "25": [4, 5], "10": 4, "5": 4, "main": 4, "jun": 4, "6": 4, "2022": 4, "18": 4, "49": 4, "26": 4, "gcc": 4, "12": 4, "linux": 4, "type": 4, "help": 4, "copyright": 4, "credit": 4, "licens": 4, "more": 4, "inform": 4, "import": 4, "secret": 4, "token_urlsaf": 4, "pgoes3qoslhxduzny_gmn6p5vwzqszqbgnb_vpupq7o": 4, "command": 4, "line": 4, "date": 4, "sha256sum": 4, "base64": 4, "head": 4, "c": 4, "echo": 4, "nwu2mze1zgm0mmvlzdg5ndnhn": 4, "after": 4, "If": 4, "miss": 4, "invalid": 4, "export": 4, "follow": 4, "default": 4, "twootfeed_config_dir": 4, "directori": 4, "twootfeed_config_fil": 4, "full": 4, "path": 4, "dir": 4, "twootfeed_log": 4, "print": 4, "consol": 4, "twootfeed_set": 4, "productionconfig": 4, "u": 4, "restart": 4, "To": 4, "sudo": 4, "nano": 4, "etc": 4, "system": 4, "templat": 4, "distribut": 4, "unit": 4, "network": 4, "target": 4, "startlimitintervalsec": 4, "simpl": 4, "alwai": 4, "restartsec": 4, "execstart": 4, "twootfeed_directori": 4, "python3": 4, "wantedbi": 4, "multi": 4, "systemctl": 4, "boot": 4, "localhost": [4, 5], "8080": [4, 5], "q": [4, 5], "tag": 4, "without": 4, "lead": 4, "home_timelin": 4, "where": 4, "store": 5, "result": 5, "social": 5, "client_id_fil": 5, "tootrss_clientcr": 5, "txt": 5, "access_token_fil": 5, "tootrss_usercr": 5, "app_nam": 5, "tootrss": 5, "identifi": 5, "languag": 5, "fr": 5, "author_nam": 5, "feed_url": 5, "timezon": 5, "europ": 5, "pari": 5, "text_length_limit": 5, "100": 5, "max_item": 5, "20": 5, "host": 5, "port": 5, "nb_worker": 5, "2": 5, "defin": 5, "en": 5, "instanc": 5, "author": 5, "maximum": 5, "minim": 5, "wsgi": 5, "calcul": 5}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"chang": 0, "log": 0, "version": 0, "0": 0, "7": 0, "2": 0, "2022": 0, "08": 0, "27": 0, "bug": 0, "fix": 0, "1": 0, "07": 0, "16": 0, "misc": 0, "15": 0, "new": 0, "featur": [0, 1], "6": 0, "8": 0, "2021": 0, "10": 0, "05": 0, "2020": 0, "03": 0, "2019": 0, "20": 0, "5": 0, "09": 0, "23": 0, "4": 0, "31": 0, "3": 0, "01": 0, "26": 0, "25": 0, "2018": 0, "17": 0, "mastodon": [0, 5], "extend": 0, "support": 0, "14": 0, "make": 0, "04": 0, "favorit": 0, "2017": 0, "12": 0, "18": 0, "descript": 1, "quick": 2, "start": 2, "develop": 2, "depend": 2, "instal": [2, 4], "test": 2, "welcom": 3, "twootfe": 3, "": 3, "document": 3, "content": 3, "usag": 4, "requir": 4, "upgrad": 4, "systemd": 4, "servic": 4, "applic": 5, "feed": 5, "paramet": 5, "twitter": 5, "app": 5}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 56}}) \ No newline at end of file diff --git a/docsrc/source/conf.py b/docsrc/source/conf.py index 67b3ef0..31945cc 100644 --- a/docsrc/source/conf.py +++ b/docsrc/source/conf.py @@ -23,7 +23,7 @@ def setup(app): # -- Project information ----------------------------------------------------- project = 'twootfeed' -copyright = '2015 - 2021, SamR1' +copyright = '2015 - 2022, SamR1' author = 'SamR1' # The full version, including alpha/beta/rc tags. diff --git a/docsrc/source/features.rst b/docsrc/source/features.rst index 5e9be1a..572dd8d 100644 --- a/docsrc/source/features.rst +++ b/docsrc/source/features.rst @@ -4,7 +4,7 @@ Features Description ~~~~~~~~~~~ -**twootfeed** generate an RSS feed from **Twitter** or **Mastodon** search and from **Mastodon** bookmarks/favorites/home timeline. +**twootfeed** generates an RSS feed from **Twitter** or **Mastodon** search and from **Mastodon** bookmarks/favorites/home timeline. The feed displays only the original tweets (not the retweets) and toots, with: @@ -15,8 +15,9 @@ The feed displays only the original tweets (not the retweets) and toots, with: - usernames - URLs -- images -- source +- images, video (mp4) and animated gif (as mp4 video) +- image description (only for Mastodon) +- source if available - location (only for Twitter) - visibility (only for Mastodon) - numbers of retweets and likes for tweets and boosts and favourites for toots diff --git a/docsrc/source/how-to-developers.rst b/docsrc/source/how-to-developers.rst index f1571c4..bba0f82 100644 --- a/docsrc/source/how-to-developers.rst +++ b/docsrc/source/how-to-developers.rst @@ -6,7 +6,7 @@ Dependencies - `Flask `_ - `Feedgenerator `_ -- `Tweepy `_ (only tested with the `Twitter Standard API `_) +- `Tweepy `_ (only tested with the `Twitter Standard v1.1 API `_) - `Mastodon.py `_ - `pytz `_ - `pyYAML `_ diff --git a/docsrc/source/index.rst b/docsrc/source/index.rst index e097232..d3aa8db 100644 --- a/docsrc/source/index.rst +++ b/docsrc/source/index.rst @@ -6,7 +6,7 @@ Welcome to twootfeed's documentation! ===================================== -**twootfeed** generate an rss feed from parsed Twitter or Mastodon search and from Mastodon bookmarks, favorites and home timeline. +**twootfeed** generates an RSS feed from parsed Twitter or Mastodon search and from Mastodon bookmarks, favorites and home timeline. .. toctree:: :maxdepth: 1 diff --git a/docsrc/source/installation.rst b/docsrc/source/installation.rst index d76629a..c9e41bc 100644 --- a/docsrc/source/installation.rst +++ b/docsrc/source/installation.rst @@ -13,18 +13,23 @@ Installation - Create and activate a virtualenv +.. code-block:: bash + + $ python -m venv .venv + $ source .venv/bin/activate + - Install from pip .. code-block:: bash - $ pip install twootfeed + (.venv) $ pip install twootfeed - Initialize the configuration file .. code-block:: bash - $ twootfeed_init + (.venv) $ twootfeed_init - Fill in fields for the client(s) you want to use in **'~/.config/twootfeed/config.yml'** : @@ -82,7 +87,7 @@ After generation, copy the value into **'config.yml'**. .. warning:: | If the token is missing or invalid, **twootfeed** will not start. -- The files location and settings can be changed with the following environment variables: +- The files location and settings can be changed by exporting the following environment variables: =========================== =============================================== =========================================================================================== variable description app default value @@ -97,7 +102,7 @@ After generation, copy the value into **'config.yml'**. .. code-block:: bash - $ twootfeed + (.venv) $ twootfeed Upgrade @@ -105,11 +110,15 @@ Upgrade - Activate the virtualenv +.. code-block:: bash + + $ source .venv/bin/activate + - Upgrade with pip .. code-block:: bash - $ pip install -U twootfeed + (.venv) $ pip install -U twootfeed - Restart the application diff --git a/setup.cfg b/setup.cfg index 2dcef73..92708ac 100644 --- a/setup.cfg +++ b/setup.cfg @@ -31,13 +31,14 @@ setup_requires = pytest-runner install_requires = beautifulsoup4==4.11.1 feedgenerator==2.0.0 - Flask==2.1.3 + Flask==2.2.2 gunicorn==20.1.0 Mastodon.py==1.5.1 - pytz==2022.1 + pytz==2022.2.1 PyYAML==6.0.0 - tweepy==4.10.0 + tweepy==4.10.1 tests_require = + flake8<5.0.0 mypy pytest-cov pytest-flake8 @@ -49,6 +50,7 @@ include_package_data = True [options.extras_require] test = + flake8<5.0.0 mypy pytest-cov pytest-flake8 diff --git a/twootfeed/__init__.py b/twootfeed/__init__.py index 6528f47..16c3e9e 100644 --- a/twootfeed/__init__.py +++ b/twootfeed/__init__.py @@ -43,10 +43,9 @@ def create_app() -> Flask: @app.route('/') def index_page() -> str: message = ( - 'The RSS feeds are available on these urls : \r\n' - 'for Twitter : http://localhost:5000/_keywords_ or ' - 'http://localhost:5000/tweets/_keywords_ ,\r\n' - 'for Mastodon : http://localhost:5000/toots/_keywords_' + 'The RSS feeds for search are available on these endpoints: ' + '"tweets?q=QUERY&token=TOKEN" for Twitter or ' + '"toots/search?q=QUERY&token=TOKEN" for Mastodon.' ) return message diff --git a/twootfeed/mastodon/generate_toots_feed.py b/twootfeed/mastodon/generate_toots_feed.py index 547ddfd..79a468a 100644 --- a/twootfeed/mastodon/generate_toots_feed.py +++ b/twootfeed/mastodon/generate_toots_feed.py @@ -54,12 +54,36 @@ def format_toot(toot: Dict, text_length_limit: int) -> Dict: if len(medialist) > 0: rss_toot['htmltext'] += '
      ' for media in medialist: + url = media.get('url') if media['type'] == 'image': rss_toot['htmltext'] += ( - f"" ) + if media['type'] in ['video', 'gifv']: + attrs = ( + 'controls' + if media['type'] == 'video' + else 'autoplay loop muted inline' + ) + small = media.get('meta', {}).get('small', {}) + width = small.get('width', 400) + height = small.get('height', 225) + preview_url = media.get('preview_url') + rss_toot['htmltext'] += ( + f" " + ) + + description = media.get('description') + if description: + rss_toot[ + 'htmltext' + ] += f"
      {description}
      " visibility_icon = get_visibility_icon(toot) rss_toot['htmltext'] += ( diff --git a/twootfeed/mastodon/routes.py b/twootfeed/mastodon/routes.py index f0bf24f..499620c 100644 --- a/twootfeed/mastodon/routes.py +++ b/twootfeed/mastodon/routes.py @@ -42,5 +42,5 @@ def toots_bookmarks_feed() -> Tuple[str, int]: @mastodon_bp.route('/toots/home_timeline', methods=['GET']) @require_token def toots_home_timeline() -> Tuple[str, int]: - """generate a rss feed authenticated user's bookmarks""" + """generate a rss feed authenticated user's home timeline""" return generate_xml(mastodon_api, mastodon_param, target='home_timeline') diff --git a/twootfeed/tests/data.py b/twootfeed/tests/data.py index 85d69c9..9e89eb5 100644 --- a/twootfeed/tests/data.py +++ b/twootfeed/tests/data.py @@ -202,7 +202,48 @@ 'small': {'w': 680, 'h': 481, 'resize': 'fit'}, 'medium': {'w': 1200, 'h': 848, 'resize': 'fit'}, }, - } + }, + { + "id": 8888888888888888888, + "id_str": "8888888888888888888", + "indices": [237, 260], + "media_url": "http://pbs.twimg.com/ext_tw_video_thumb/" + "1212121212121212121/pu/img/DxDxDxDxDxDxDxD.jpg", + "media_url_https": "https://pbs.twimg.com/ext_tw_video_thumb/" + "1212121212121212121/pu/img/" + "DxDxDxDxDxDxDxD.jpg", + "url": "https://t.co/AAAAAAAAAA", + "display_url": "pic.twitter.com/AAAAAAAAAA", + "expanded_url": "https://twitter.com/CROSHDF/status/" + "1212121212121212121/video/1", + "type": "video", + "sizes": { + "thumb": {"w": 150, "h": 150, "resize": "crop"}, + "small": {"w": 383, "h": 680, "resize": "fit"}, + "medium": {"w": 675, "h": 1200, "resize": "fit"}, + "large": {"w": 1080, "h": 1920, "resize": "fit"}, + }, + }, + { + "id": 7777777777777777777, + "id_str": "7777777777777777777", + "indices": [67, 90], + "media_url": "http://pbs.twimg.com/tweet_video_thumb/" + "DDDDDDDDDDDDDDD.jpg", + "media_url_https": "https://pbs.twimg.com/tweet_video_thumb/" + "DDDDDDDDDDDDDDD.jpg", + "url": "https://t.co/CCCCCCCCCC", + "display_url": "pic.twitter.com/ETn6mEs0vP", + "expanded_url": "https://twitter.com/UserA/status/" + "7777777777777777777/photo/1", + "type": "animated_gif", + "sizes": { + "small": {"w": 498, "h": 448, "resize": "fit"}, + "thumb": {"w": 150, "h": 150, "resize": "crop"}, + "large": {"w": 498, "h": 448, "resize": "fit"}, + "medium": {"w": 498, "h": 448, "resize": "fit"}, + }, + }, ], }, 'extended_entities': { @@ -247,6 +288,92 @@ 'small': {'w': 680, 'h': 481, 'resize': 'fit'}, }, }, + { + "id": 8888888888888888888, + "id_str": "8888888888888888888", + "indices": [237, 260], + "media_url": "http://pbs.twimg.com/ext_tw_video_thumb/" + "1212121212121212121/pu/img/DxDxDxDxDxDxDxD.jpg", + "media_url_https": "https://pbs.twimg.com/ext_tw_video_thumb/" + "1212121212121212121/pu/img/" + "DxDxDxDxDxDxDxD.jpg", + "url": "https://t.co/AAAAAAAAAA", + "display_url": "pic.twitter.com/AAAAAAAAAA", + "expanded_url": "https://twitter.com/CROSHDF/status/" + "1212121212121212121/video/1", + "type": "video", + "sizes": { + "thumb": {"w": 150, "h": 150, "resize": "crop"}, + "small": {"w": 383, "h": 680, "resize": "fit"}, + "medium": {"w": 675, "h": 1200, "resize": "fit"}, + "large": {"w": 1080, "h": 1920, "resize": "fit"}, + }, + "video_info": { + "aspect_ratio": [9, 16], + "duration_millis": 56704, + "variants": [ + { + "content_type": "application/x-mpegURL", + "url": "https://video.twimg.com/ext_tw_video/" + "1212121212121212121/pu/pl/ttEz4_ebdrQaB5EW" + ".m3u8?tag=12&container=fmp4", + }, + { + "bitrate": 950000, + "content_type": "video/mp4", + "url": "https://video.twimg.com/ext_tw_video/" + "1212121212121212121/pu/vid/480x852/" + "eVydKjMo5pY7qWYj.mp4?tag=12", + }, + { + "bitrate": 632000, + "content_type": "video/mp4", + "url": "https://video.twimg.com/ext_tw_video/" + "1212121212121212121/pu/vid/320x568/" + "S5c9t3ytXZ5UJ9Ag.mp4?tag=12", + }, + { + "bitrate": 2176000, + "content_type": "video/mp4", + "url": "https://video.twimg.com/ext_tw_video/" + "1212121212121212121/pu/vid/720x1280/" + "NuzHqlk2lXf2AFFI.mp4?tag=12", + }, + ], + }, + "additional_media_info": {"monetizable": False}, + }, + { + "id": 7777777777777777777, + "id_str": "7777777777777777777", + "indices": [67, 90], + "media_url": "http://pbs.twimg.com/tweet_video_thumb/" + "DDDDDDDDDDDDDDD.jpg", + "media_url_https": "https://pbs.twimg.com/tweet_video_thumb/" + "DDDDDDDDDDDDDDD.jpg", + "url": "https://t.co/CCCCCCCCCC", + "display_url": "pic.twitter.com/ETn6mEs0vP", + "expanded_url": "https://twitter.com/UserA/status/" + "7777777777777777777/photo/1", + "type": "animated_gif", + "sizes": { + "small": {"w": 498, "h": 448, "resize": "fit"}, + "thumb": {"w": 150, "h": 150, "resize": "crop"}, + "large": {"w": 498, "h": 448, "resize": "fit"}, + "medium": {"w": 498, "h": 448, "resize": "fit"}, + }, + "video_info": { + "aspect_ratio": [249, 224], + "variants": [ + { + "bitrate": 0, + "content_type": "video/mp4", + "url": "https://video.twimg.com/tweet_video/" + "DDDDDDDDDDDDDDD.mp4", + } + ], + }, + }, ] }, 'metadata': {'iso_language_code': 'fr', 'result_type': 'recent'}, @@ -348,7 +475,13 @@ 'example.com/test/this-is-…
      ' # noqa 'Source: Twitter for Android
      ' # noqa '' # noqa - '
      ' # noqa + '' # noqa + ' ' + '
      ' ' ♻ : 4, ♥ : 8' '
      ' '', @@ -686,7 +819,59 @@ }, }, 'description': None, - } + }, + { + "id": 10872710422, + "type": "video", + "url": "https://files.mastodon.social/cache/media_attachments/files/888/888/888/888/888/888/original/b1b1b1b1b1b1b1b1.mp4", # noqa + "preview_url": "https://files.mastodon.social/cache/media_attachments/files/108/778/808/662/710/422/small/b1b1b1b1b1b1b1b1.png", # noqa + "remote_url": None, + "preview_remote_url": None, + "text_url": None, + "meta": { + "original": { + "width": 360, + "height": 450, + "frame_rate": "10400/347", + "duration": 19.109, + "bitrate": 572691, + }, + "small": { + "width": 320, + "height": 400, + "size": "320x400", + "aspect": 0.8, + }, + }, + "description": None, + "blurhash": "UcvWGoxGxZRv~qxuxuj[DioLt7oftRRjWVvB", + }, + { + "id": 108806907390, + "type": "gifv", + "url": "https://files.mastodon.social/cache/media_attachments/files/777/777/777/777/777/777/original/d4d4d4d4d4d4d4d4.mp4", # noqa + "preview_url": "https://files.mastodon.social/cache/media_attachments/files/777/777/777/777/777/777/small/d4d4d4d4d4d4d4d4.png", # noqa + "remote_url": None, + "preview_remote_url": None, + "text_url": None, + "meta": { + "original": { + "width": 1156, + "height": 720, + "frame_rate": "60/1", + "duration": 18.517, + "bitrate": 1660750, + }, + "small": { + "width": 400, + "height": 249, + "size": "400x249", + "aspect": 1.606425702811245, + }, + }, + "description": None, + "blurhash": "UvEfv#tQk8%2~Wogozxavtt7s;%2Iot7smvz", + }, ], 'mentions': [], 'tags': [ @@ -709,6 +894,14 @@ '

      This is a

      ' # noqa 'Source: Twidere for Android
      ' '' # noqa + ' ' + ' ' '
      ♻ : 0, ✰ : 0, 🌐

      ', 'text': 'This is a ... ', } diff --git a/twootfeed/tests/test_default_route.py b/twootfeed/tests/test_default_route.py index 9dd7e43..76eeb4d 100644 --- a/twootfeed/tests/test_default_route.py +++ b/twootfeed/tests/test_default_route.py @@ -14,8 +14,7 @@ def test_default_route(app: Flask) -> None: assert response.status_code == 200 data = response.data.decode() assert data == ( - 'The RSS feeds are available on these urls : \r\n' - 'for Twitter : http://localhost:5000/_keywords_ ' - 'or http://localhost:5000/tweets/_keywords_ ,\r\n' - 'for Mastodon : http://localhost:5000/toots/_keywords_' + 'The RSS feeds for search are available on these endpoints: ' + '"tweets?q=QUERY&token=TOKEN" for Twitter or ' + '"toots/search?q=QUERY&token=TOKEN" for Mastodon.' ) diff --git a/twootfeed/tests/test_twitter_feed_generation.py b/twootfeed/tests/test_twitter_feed_generation.py index 0d5f7e4..68f673a 100644 --- a/twootfeed/tests/test_twitter_feed_generation.py +++ b/twootfeed/tests/test_twitter_feed_generation.py @@ -18,12 +18,12 @@ tweet_2, tweet_20_feed, ) -from .utils import ToDotNotation, TwitterApi +from .utils import Tweet, TwitterApi def test_format_tweet() -> None: - assert format_tweet(ToDotNotation(tweet_1)) == formatted_tweet_1 - assert format_tweet(ToDotNotation(tweet_2)) == formatted_tweet_2 + assert format_tweet(Tweet(tweet_1)) == formatted_tweet_1 + assert format_tweet(Tweet(tweet_2)) == formatted_tweet_2 @patch('tweepy.Cursor') diff --git a/twootfeed/tests/utils.py b/twootfeed/tests/utils.py index 13542ee..d405876 100644 --- a/twootfeed/tests/utils.py +++ b/twootfeed/tests/utils.py @@ -2,69 +2,42 @@ # source: https://stackoverflow.com/a/32107024 -class ToDotNotation(dict): +class Tweet(dict): def __init__(self, *args: Any, **kwargs: Any) -> None: - super(ToDotNotation, self).__init__(*args, **kwargs) + super(Tweet, self).__init__(*args, **kwargs) for arg in args: if isinstance(arg, dict): for k, v in arg.items(): - self[k] = ToDotNotation(v) if isinstance(v, dict) else v + self[k] = Tweet(v) if isinstance(v, dict) else v if kwargs: for k, v in kwargs.items(): - self[k] = ToDotNotation(v) if isinstance(v, dict) else v + self[k] = Tweet(v) if isinstance(v, dict) else v def __getattr__(self, attr: str) -> Any: return self.get(attr) - def __setattr__(self, key: str, value: Any) -> None: - self.__setitem__(key, value) - - def __setitem__(self, key: str, value: Any) -> None: - super(ToDotNotation, self).__setitem__(key, value) - self.__dict__.update({key: value}) - - def __delattr__(self, item: Any) -> None: - self.__delitem__(item) - - def __delitem__(self, key: str) -> None: - super(ToDotNotation, self).__delitem__(key) - del self.__dict__[key] - - -class ToDotNotationTweepy(ToDotNotation): - def __init__(self, *args: Any, **kwargs: Any) -> None: - super(ToDotNotation, self).__init__(*args, **kwargs) - for arg in args: - if isinstance(arg, dict): - for k, v in arg.items(): - self[k] = ToDotNotation(v) if isinstance(v, dict) else v - - if kwargs: - for k, v in kwargs.items(): - self[k] = ToDotNotation(v) if isinstance(v, dict) else v - class Tweepy: def __init__(self, tweets: List): self.tweet_pages = self.items_in_pages(tweets) - self.tweets = [ToDotNotationTweepy(tweet) for tweet in tweets] + self.tweets = [Tweet(tweet) for tweet in tweets] def Cursor(self, *args: Any, **kwargs: Any) -> 'Tweepy': return self - def pages(self) -> List[List[ToDotNotationTweepy]]: + def pages(self) -> List[List[Tweet]]: return self.tweet_pages def items(self) -> List: return self.tweets @staticmethod - def items_in_pages(tweets: List[Dict]) -> List[List[ToDotNotationTweepy]]: + def items_in_pages(tweets: List[Dict]) -> List[List[Tweet]]: pages = [] current_page = [] for tweet_index, tweet in enumerate(tweets): - current_page.append(ToDotNotationTweepy(tweet)) + current_page.append(Tweet(tweet)) if tweet_index > 4 or tweet_index == len(tweets) - 1: pages.append(current_page) current_page = [] diff --git a/twootfeed/twitter/generate_tweets_feed.py b/twootfeed/twitter/generate_tweets_feed.py index 05c84e5..77b12a8 100644 --- a/twootfeed/twitter/generate_tweets_feed.py +++ b/twootfeed/twitter/generate_tweets_feed.py @@ -82,7 +82,38 @@ def format_tweet(tweet: tweepy.tweet.Tweet) -> Dict: + 'target="_blank">' ) - + if media.get('type') in ['animated_gif', 'video']: + attrs = ( + 'controls' + if media['type'] == 'video' + else 'autoplay loop muted inline' + ) + video_info = media.get('video_info', {}) + variants = video_info.get('variants', []) + preview_url = media.get('media_url_https') + url = None + bitrate = None + for variant in variants: + if variant.get('content_type') != 'video/mp4': + continue + if bitrate is None or bitrate > variant.get( + 'bitrate' + ): + bitrate = variant.get('bitrate') + url = variant.get('url') + if not url: + rss_tweet['htmltext'] += ''.format( + preview_url + ) + else: + rss_tweet['htmltext'] += ( + f" " + ) location = tweet.place if location is not None: rss_tweet['htmltext'] += '
      Location: {}'.format(