diff --git a/README.md b/README.md index 9307055..6a38501 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ scrubbing](https://sjp.pwn.pl/sjp/;2527372). It is pronounced as *shoorubooru*. ## Features - Post content: images (JPG, PNG, GIF, animated GIF), videos (MP4, WEBM), Flash animations -- Ability to retrieve web video content using [youtube-dl](https://github.com/ytdl-org/youtube-dl) +- Ability to retrieve web video content using [yt-dlp](https://github.com/yt-dlp/yt-dlp) - Post comments - Post notes / annotations, including arbitrary polygons - Rich JSON REST API ([see documentation](doc/API.md)) diff --git a/client/css/comment-control.styl b/client/css/comment-control.styl index 0d5959b..21bbf72 100644 --- a/client/css/comment-control.styl +++ b/client/css/comment-control.styl @@ -127,6 +127,10 @@ $comment-border-color = #DDD color: mix($main-color, $inactive-link-color-darktheme) .comment-content + p + word-wrap: normal + word-break: break-all + ul, ol list-style-position: inside margin: 1em 0 diff --git a/client/css/core-general.styl b/client/css/core-general.styl index 3f48e82..d25c5f6 100644 --- a/client/css/core-general.styl +++ b/client/css/core-general.styl @@ -300,10 +300,10 @@ a .access-key background-size: 20px 20px img opacity: 0 - width: inherit + width: 100% height: 100% video - width: inherit + width: 100% height: 100% .flexbox-dummy diff --git a/client/js/controllers/pool_list_controller.js b/client/js/controllers/pool_list_controller.js index 91d655c..a66f816 100644 --- a/client/js/controllers/pool_list_controller.js +++ b/client/js/controllers/pool_list_controller.js @@ -43,6 +43,8 @@ class PoolListController { this._headerView.addEventListener( "submit", (e) => this._evtSubmit(e), + ); + this._headerView.addEventListener( "navigate", (e) => this._evtNavigate(e) ); diff --git a/doc/API.md b/doc/API.md index 63a50a2..00ee75a 100644 --- a/doc/API.md +++ b/doc/API.md @@ -54,7 +54,7 @@ - [Deleting pool category](#deleting-pool-category) - [Setting default pool category](#setting-default-pool-category) - Pools - - [Listing pools](#listing-pool) + - [Listing pools](#listing-pools) - [Creating pool](#creating-pool) - [Updating pool](#updating-pool) - [Getting pool](#getting-pool) @@ -165,9 +165,9 @@ way. The files, however, should be passed as regular fields appended with a accepts a file named `content`, the client should pass `{"contentUrl":"http://example.com/file.jpg"}` as a part of the JSON message body. When creating or updating post content using this method, the server can -also be configured to employ [youtube-dl](https://github.com/ytdl-org/youtube-dl) -to download content from popular sites such as youtube, gfycat, etc. Access to -youtube-dl can be configured with the `'uploads:use_downloader'` permission +also be configured to employ [yt-dlp](https://github.com/yt-dlp/yt-dlp) to +download content from popular sites such as youtube, gfycat, etc. Access to +yt-dlp can be configured with the `'uploads:use_downloader'` permission Finally, in some cases the user might want to reuse one file between the requests to save the bandwidth (for example, reverse search + consecutive @@ -323,7 +323,7 @@ data. { "name": , "color": , - "order": // optional + "order": } ``` @@ -1389,7 +1389,7 @@ data. ## Creating pool - **Request** - `POST /pools/create` + `POST /pool` - **Input** @@ -2491,7 +2491,7 @@ One file together with its metadata posted to the site. ## Micro post **Description** -A [post resource](#post) stripped down to `name` and `thumbnailUrl` fields. +A [post resource](#post) stripped down to `id` and `thumbnailUrl` fields. ## Note **Description** diff --git a/server/Dockerfile b/server/Dockerfile index 487f192..3e4dadf 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -23,15 +23,15 @@ RUN apk --no-cache add \ py3-pillow \ py3-pynacl \ py3-tz \ - py3-pyrfc3339 \ - && pip3 install --no-cache-dir --disable-pip-version-check \ + py3-pyrfc3339 +RUN pip3 install --no-cache-dir --disable-pip-version-check \ "alembic>=0.8.5" \ "coloredlogs==5.0" \ "pyheif==0.6.1" \ "heif-image-plugin>=0.3.2" \ - youtube_dl \ - "pillow-avif-plugin>=1.1.0" \ - && apk --no-cache del py3-pip + yt-dlp \ + "pillow-avif-plugin~=1.1.0" +RUN apk --no-cache del py3-pip COPY ./ /opt/app/ RUN rm -rf /opt/app/szurubooru/tests diff --git a/server/requirements.txt b/server/requirements.txt index 16b29ff..ffe18f0 100644 --- a/server/requirements.txt +++ b/server/requirements.txt @@ -3,7 +3,7 @@ certifi>=2017.11.5 coloredlogs==5.0 heif-image-plugin==0.3.2 numpy>=1.8.2 -pillow-avif-plugin>=1.1.0 +pillow-avif-plugin~=1.1.0 pillow>=4.3.0 psycopg2-binary>=2.6.1 pyheif==0.6.1 @@ -12,4 +12,4 @@ pyRFC3339>=1.0 pytz>=2018.3 pyyaml>=3.11 SQLAlchemy>=1.0.12, <1.4 -youtube_dl +yt-dlp diff --git a/server/szurubooru/func/net.py b/server/szurubooru/func/net.py index c53a62e..d6aa95e 100644 --- a/server/szurubooru/func/net.py +++ b/server/szurubooru/func/net.py @@ -64,7 +64,7 @@ def download(url: str, use_video_downloader: bool = False) -> bytes: def _get_youtube_dl_content_url(url: str) -> str: - cmd = ["youtube-dl", "--format", "best", "--no-playlist"] + cmd = ["yt-dlp", "--format", "best", "--no-playlist"] if config.config["user_agent"]: cmd.extend(["--user-agent", config.config["user_agent"]]) cmd.extend(["--get-url", url]) diff --git a/server/szurubooru/search/configs/post_search_config.py b/server/szurubooru/search/configs/post_search_config.py index ddc003b..8d4672d 100644 --- a/server/szurubooru/search/configs/post_search_config.py +++ b/server/szurubooru/search/configs/post_search_config.py @@ -122,6 +122,34 @@ def _pool_filter( )(query, criterion, negated) +def _category_filter( + query: SaQuery, criterion: Optional[criteria.BaseCriterion], negated: bool +) -> SaQuery: + assert criterion + + # Step 1. find the id for the category + q1 = db.session.query(model.TagCategory.tag_category_id).filter( + model.TagCategory.name == criterion.value + ) + + # Step 2. find the tags with that category + q2 = db.session.query(model.Tag.tag_id).filter( + model.Tag.category_id.in_(q1) + ) + + # Step 3. find all posts that have at least one of those tags + q3 = db.session.query(model.PostTag.post_id).filter( + model.PostTag.tag_id.in_(q2) + ) + + # Step 4. profit + expr = model.Post.post_id.in_(q3) + if negated: + expr = ~expr + + return query.filter(expr) + + class PostSearchConfig(BaseSearchConfig): def __init__(self) -> None: self.user = None # type: Optional[model.User] @@ -349,6 +377,7 @@ class PostSearchConfig(BaseSearchConfig): ), ), (["pool"], _pool_filter), + (["category"], _category_filter), ] ) diff --git a/server/szurubooru/tests/search/configs/test_post_search_config.py b/server/szurubooru/tests/search/configs/test_post_search_config.py index 4fb8191..b86fa27 100644 --- a/server/szurubooru/tests/search/configs/test_post_search_config.py +++ b/server/szurubooru/tests/search/configs/test_post_search_config.py @@ -863,3 +863,55 @@ def test_tumbleweed( db.session.flush() verify_unpaged("special:tumbleweed", [4]) verify_unpaged("-special:tumbleweed", [1, 2, 3]) + + +@pytest.mark.parametrize( + "input,expected_post_ids", + [ + ("category:cat1", [1, 2, 3]), + ("category:cat2", [3, 4]), + ], +) +def test_search_by_tag_category( + verify_unpaged, + post_factory, + tag_factory, + tag_category_factory, + input, + expected_post_ids, +): + cat1 = tag_category_factory(name="cat1") + cat2 = tag_category_factory(name="cat2") + tag1 = tag_factory(names=["t1"], category=cat1) + tag2 = tag_factory(names=["t2"], category=cat1) + tag3 = tag_factory(names=["t3"], category=cat2) + + post1 = post_factory(id=1) + post1.tags.append(tag1) + + post2 = post_factory(id=2) + post2.tags.append(tag2) + + post3 = post_factory(id=3) + post3.tags.append(tag1) + post3.tags.append(tag3) + + post4 = post_factory(id=4) + post4.tags.append(tag3) + + post5 = post_factory(id=5) + + db.session.add_all( + [ + tag1, + tag2, + tag3, + post1, + post2, + post3, + post4, + post5, + ] + ) + db.session.flush() + verify_unpaged(input, expected_post_ids)