Commit Graph

2833 Commits

Author SHA1 Message Date
evazion
84212acfae Merge pull request #4905 from nottalulah/remove-locks-from-autocomplete
remove references to locks
2021-10-25 21:18:36 -05:00
evazion
f1b5c34b4d posts: show length of videos and animations in thumbnails.
Show the length of videos and animated posts in the thumbnail. The
length is shown the top left corner in MM:SS format. This replaces the
play button icon.

Show a speaker icon instead of a music note icon for posts with sound.

Doing this requires doing `.includes(:media_asset)` in a bunch of
places to avoid N+1 queries when we access the post's duration.
2021-10-25 02:56:55 -05:00
Lily
647848b499 remove references to locks 2021-10-24 15:16:48 -03:00
evazion
8d5e0a5b58 replacements: don't delete replaced files.
Don't delete replaced files after 30 days. There are only about 30k
replacements in total, so the cost of keeping replaced files is
negligible. It was also wrong because the media asset wasn't destroyed
too, so there were active media assets with missing files.
2021-10-24 04:35:13 -05:00
evazion
f78378cc69 recommendations: reduce cache lifetime to 5 minutes.
These calls aren't actually slow and don't need to be cached for long
periods of time.
2021-10-21 00:46:47 -05:00
evazion
0221ecdf29 uploads: remove useless code. 2021-10-18 06:25:02 -05:00
evazion
748fdf33d4 uploads: don't autotag sound on videos.
Don't automatically add the sound tag to videos. This was incorrect
nearly 20% of the time because of silent audio tracks. This error rate
is too high.

https://danbooru.donmai.us/posts?tags=exif:Track2:AudioChannels+-sound
https://danbooru.donmai.us/posts?tags=exif:Track1:AudioChannels+-sound
2021-10-18 06:16:47 -05:00
evazion
bc506ed1b8 uploads: refactor to simplify ugoira-handling and replacements:
* Make it so replacing a post doesn't generate a dummy upload as a side effect.
* Make it so you can't replace a post with itself (the post should be regenerated instead).
* Refactor uploads and replacements to save the ugoira frame data when
  the MediaAsset is created, not when the post is created. This way it's
  possible to view the ugoira before the post is created.
* Make `download_file!` in the Pixiv source strategy return a MediaFile
  with the ugoira frame data already attached to it, instead of returning it
  in the `data` field then passing it around separately in the `context`
  field of the upload.
2021-10-18 05:18:46 -05:00
evazion
1d034a3223 media assets: move more file-handling logic into MediaAsset.
Move more of the file-handling logic from UploadService and
StorageManager into MediaAsset. This is part of refactoring posts and
uploads to allow multiple images per post.
2021-10-18 00:10:29 -05:00
evazion
8b3ab04724 media file: fix calculation of video/animation duration.
Fix how the duration of videos and animated GIFs / PNGs is calculated.
If we can't determine the duration from the file metadata, then play the
entire video or animation back using FFmpeg and scrape the duration and
frame count.

This is necessary for things like WebM files where the duration metadata
is optional, or animated GIFs and PNGs that don't have a duration field
in the metadata, only a frame count and a sequence of frame delays.
2021-10-17 20:15:51 -05:00
evazion
2845164872 search: support quoted phrases, OR, and NOT operators in full-text search.
Make all full-text search fields support quoted phrases and OR and NOT
operators.

This affects all text search fields (any search field that looks like `*_matches`).

Examples:

* hakurei reimu   - matches anything containing the words "hakurei" and "reimu", in any order.
* hakuri or reimu - matches either "hakurei" or "reimu".
* hakurei -reimu  - matches "hakurei" but not "reimu"
* "hakurei reimu" - matches the exact phrase "hakurei reimu"
* "reimu hakurei" - matches the exact phrase "reimu hakurei"

* https://danbooru.donmai.us/notes?search[body_matches]=reimu+hakurei
* https://danbooru.donmai.us/notes?search[body_matches]=reimu+or+hakurei
* https://danbooru.donmai.us/notes?search[body_matches]=reimu+-hakurei
* https://danbooru.donmai.us/notes?search[body_matches]="hakurei+reimu"
* https://danbooru.donmai.us/notes?search[body_matches]="reimu+hakurei"

The phrase search ability partially fixes #4536 (Inconsistent behavior
of search function for comments/forums).

See `websearch_to_tsquery` [1] for full details of the search syntax.

[1]: https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES
2021-10-16 19:13:09 -05:00
evazion
e3b836b506 Refactor full-text search to get rid of tsvector columns.
Refactor full-text search on several tables (comments, dmails,
forum_posts, forum_topics, notes, and wiki_pages) to use to_tsvector
expression indexes instead of dedicated tsvector columns. This way
full-text search works the same way across all tables.

API changes:

* Changed /wiki_pages.json?search[body_matches] to match against only
  the body. Before `body_matches` matched against both the title and the body.

* Added /wiki_pages.json?search[title_or_body_matches] to match against
  both the title and the body.

* Fixed /dmails.json?search[message_matches] to match against both the
  title and body when doing a wildcard search. Before a wildcard search
  only matched against the body.

* Added /dmails.json?search[body_matches] to match against only the dmail body.
2021-10-16 07:44:27 -05:00
evazion
c0f744f84d Fix #4893: Add a FIELD_present parameter variation for text fields.
Usage:

* https://danbooru.donmai.us/wiki_pages.json?search[body_present]=true
* https://danbooru.donmai.us/wiki_pages.json?search[body_present]=false
2021-10-13 04:10:23 -05:00
evazion
206a4b5de5 docker: avoid rebuilding CSS/JS assets on every commit.
Restructure the Dockerfile and the CSS/JS files so that we only rebuild
the CSS and JS when they change, not on every commit.

Before it took several minutes to rebuild the Docker image after every
commit, even when the JS/CSS files didn't change. This also made pulling
images slower.

This requires refactoring the CSS and JS to not use embedded Ruby (ERB)
templates, since this made the CSS and JS dependent on the Ruby
codebase, which is why we had to rebuild the assets after every Ruby
change.
2021-10-13 02:48:30 -05:00
evazion
587a9d0c8f tags: move tag category definitions out of the config file.
Move all the code for defining tag categories from the config file to
TagCategory. It didn't belong in the config because it's not possible to
add new tag categories purely in the config without editing other things
like the CSS.

Also change it so that tag colors are hardcoded in the CSS instead of
generated using ERB. Generating the CSS in ERB meant that the Docker
build had to recompile the CSS on every commit, even when it didn't
change, because it relied on Ruby code outside the CSS that we couldn't
guarantee didn't change.
2021-10-12 21:17:17 -05:00
evazion
92e20713e3 search: fixup hardcoded small search threshold.
Fixup for f6abf39eb.
2021-10-12 19:01:31 -05:00
evazion
f6abf39ebc search: try to optimize slow searches.
Try to optimize certain types of common slow searches:

* Searches for mutually-exclusive tags (e.g. `1girl multiple_girls`,
  `touhou solo -1girl -1boy`)
* Relatively large tags that are heavily skewed towards old posts
  (e.g. lucky_star, haruhi_suzumiya_no_yuuutsu, inazuma_eleven_(series),
  imageboard_desourced).
* Mid-sized tags in the <30k post range that Postgres thinks are
  big enough for a post id index scan, but a tag index scan is faster.

The general pattern is Postgres not using the tag index because it
thinks scanning down the post id index would be faster, but it's
actually much slower because it degrades to a full table scan. This
usually happens when Postgres thinks a tag is larger or more common than
it really is. Here we try to force Postgres into using the tag index
when we know the search is small.

One case that is still slow is `2girls -multiple_girls`. This returns no
results, but we can't know that without searching all of `2girls`. The
general case is searching for `A -B` where A is a subset of B and A and B
are both large tags.

Hopefully fixes #581, #654, #743, #1020, #1039, #1421, #2207, #4070,
 #4337, #4896, and various other issues raised over the years regarding
slow searches.
2021-10-12 02:30:30 -05:00
evazion
0b22e873c9 search: cache timed out search counts.
When a search is performed, we cache the post count so we don't have to
calculate it again every time the user switches pages. However, if the
count times out, we didn't cache it before, causing us to do a slow
count on every page load. This usually happens on multi-tag searches
that return a lot of results, `1girl solo` for example.

This changes it so that the count is cached even when it times out. This
will speed up large multi-tag searches.

This also changes it so that the count is cached for a fixed 5 minutes.
Before it was variable based on the size of the count, but this probably
didn't make much difference.
2021-10-12 01:33:21 -05:00
evazion
f155023b77 posts: remove unused exception classes. 2021-10-11 18:58:15 -05:00
evazion
7976323f7a wiki pages: change tsvector update trigger to not use test_parser.
Change the wiki_pages tsvector_update_trigger to use
`pg_catalog.english` instead of `public.danbooru`. This changes how wiki
page text is parsed for full-text search to use the standard English
parser instead of test_parser. This is to prepare for dropping
test_parser. Using test_parser here was wrong anyway because it meant
that punctuation wasn't removed from words when indexing wiki pages for
full-text search.
2021-10-11 03:34:47 -05:00
evazion
37a8dc5dbd posts: use string_to_array index for tag searches.
Use the `string_to_array(tag_string, ' ')` index instead of the
`tag_index` for tag searches. The string_to_array index lets us treat
the tag_string as an array for searching purposes. This lets us get rid
of the tag_index column and the test_parser dependency in the future.
2021-10-10 22:00:10 -05:00
evazion
1653392361 posts: stop updating fav_string attribute.
Stop updating the fav_string attribute on posts. The column still exists
on the table, but is no longer used or updated.

Like the pool_string in 7d503f08, the fav_string was used in the past to
facilitate `fav:X` searches. Posts had a hidden fav_string column that
contained a list of every user who favorited the post. These were
treated like fake hidden tags on the post so that a search for `fav:X`
was treated like a tag search.

The fav_string attribute has been unused for search purposes for a while
now. It was only kept because of technicalities that required
departitioning the favorites table first (340e1008e) before it could be
removed. Basically, removing favorites with `@favorite.destroy` was
slow because Rails always deletes object by ID, but we didn't have an
index on favorites.id, and we couldn't easily add one until the
favorites table was departitioned.

Fixes #4652. See https://github.com/danbooru/danbooru/issues/4652#issuecomment-754993802
for more discussion of issues caused by the fav_string (in short: write
amplification, post table bloat, and favorite inconsistency problems).
2021-10-09 22:36:26 -05:00
evazion
5ce36b482f maintenance: disable amcheck job.
Creates too much load and causes creating favorites to time out.
2021-10-09 11:45:36 -05:00
evazion
8b0d58130c posts: add workaround to avoid falsely delete pending posts.
Add a temporary workaround for the database index corruption bug. Add a
check to skip deleting pending posts if they're not really pending.
2021-10-08 21:47:56 -05:00
evazion
c4eeeb8531 search: optimize counting posts for fav: and pool: searches.
Optimize counting the number of posts returned by fav:<name> and
pool:<name> searches. Use cached counts to avoid slow count(*) queries
for users with lots of favorites.
2021-10-08 21:26:42 -05:00
evazion
26a411ba27 favorites: include favorites in bigquery exports.
Include the favorites table in the nightly database dumps in BigQuery.
Previously we couldn't do this because we didn't have an index on
the favorite ID, which we needed to iterate across the table efficiently.

Note that this doesn't include private favorites. Note also that if a
user switches their favorites from private to public, then their
favorites will begin to appear in these dumps.
2021-10-08 21:26:42 -05:00
evazion
340e1008e9 favorites: merge favorites subtables.
Merge the 100 favorite subtables into a single table.

Previously the favorites table was partitioned by user id into 100
subtables to try to make searching by user id faster. This wasn't really
necessary and probably slower than just making an index on
(favorites.user_id, favorites.id) to satisfy ordfav searches. BTree
indexes are logarithmic so dividing an index by 100 doesn't make it 100
times faster to search; instead it just removes a layer or two from the
tree.

This also adds a uniqueness index on (user_id, post_id) to prevent
duplicate favorites. Previously we had to check for duplicates at the
application layer, which required careful locking to do it correctly.

Finally, this adds an index on favorites.id, which was surprisingly
missing before. This made ordering and deleting favorites by id really
slow because it degraded to a sequential scan.
2021-10-08 21:26:42 -05:00
evazion
595e02ab45 posts: add duration:<x> and order:duration metatags.
Add duration:<x> and order:duration metatags for searching animated
posts by duration.

https://danbooru.donmai.us/posts?tags=animated+duration:<5.0
https://danbooru.donmai.us/posts?tags=animated+duration:>60
https://danbooru.donmai.us/posts?tags=animated+order:duration
2021-10-07 03:21:08 -05:00
evazion
2595f18b2f posts: fix calculation of animated PNG duration.
Fix certain animated PNGs returning NaN as the duration because the
frame rate was being reported as "0/0" by FFMpeg. This happens when the
animation has zero delay between frames. This is supposed to mean a PNG
with an infinitely fast frame rate, but in practice browsers limit it to
around 10FPS. The exact frame rate browsers will use is unknown and
implementation defined.
2021-10-06 21:04:36 -05:00
evazion
950bc608c2 maintenance: add job to check for database corruption.
Add a job to run pg_amcheck hourly to check for corrupt database indexes.

https://www.postgresql.org/docs/14/app-pgamcheck.html
2021-10-06 08:08:52 -05:00
nonamethanks
45313c56a6 Lofter: fix tag extraction 2021-10-04 14:21:07 +02:00
evazion
627e8e1013 cron: fix undefined variable in exception handler (again)
Fixup for a1d4408c2.
2021-09-29 06:04:28 -05:00
evazion
4a525c7473 cron: fix maintenance tasks failing to run.
Fix maintenance tasks failing to run in production. In production they
were losing the database connection and not re-establishing it, so they
couldn't queue jobs. `ApplicationRecord.verify!` will check if the
connection is lost and re-establish it if it is.

The database connection was being lost because in production we use a
Kubernetes service IP for the database IP, which is essentially a
virtual IP that maps to the real IP. This mapping is implemented with
IPVS[1][2], which has a default idle connection timeout of 5 minutes. If
the connection isn't used for more than 5 minutes, then it's closed.
Since maintenance only runs once an hour, the database connection would
be lost because it was idle for too long.

1: https://kubernetes.io/docs/concepts/services-networking/service/#proxy-mode-ipvs
2: https://kubernetes.io/blog/2018/07/09/ipvs-based-in-cluster-load-balancing-deep-dive/
2021-09-28 18:06:57 -05:00
evazion
a1d4408c29 cron: fix undefined variable in exception handler. 2021-09-28 16:34:05 -05:00
evazion
126046cb69 posts: remove rating, note, and status locks.
Remove the ability for users to lock ratings, note, and post statuses.

Historically the majority of locked posts were from 10+ years ago when
certain users habitually locked ratings and notes on every post they
touched for no reason. Nowadays most posts have been unlocked. Only a
handful of locked posts are left, none of which deserve to be locked.

The is_rating_locked, is_note_locked, and is_status_locked columns still
exist in the database, but aren't used.
2021-09-27 22:32:30 -05:00
evazion
738be825ff twitter: include artist name in source URLs on post pages.
Show Twitter sources on post pages like this:

    https://twitter.com/BOW999/status/1261877313349640194

and not like this:

    https://twitter.com/i/web/status/1261877313349640194

We originally removed the artist name because the link would be broken
when the artist changed their name. This is no longer the case.
2021-09-27 11:07:25 -05:00
evazion
3835a63771 cron: fix tasks not being logged.
Fix maintenance tasks not being logged by the cron daemon because
in production the log level defaulted to `error` instead of `info`.
2021-09-27 10:43:06 -05:00
evazion
0e901b2f84 media file: get duration of animated GIFs, PNGs, and ugoiras.
Add methods to MediaFile to calculate the duration, frame count, and
frame rate of animated GIFs, PNGs, Ugoiras, and videos.

Some considerations:

* It's possible to have a GIF or PNG that's technically animated but
  just has one frame. These are treated as non-animated images.

* It's possible to have an animated GIF that has an unspecified
  frame rate. In this case we assume the frame rate is 10 FPS; this is
  browser dependent and may not be correct.

* Animated GIFs, PNGs, and Ugoiras all support variable frame rates.
  Technically, each frame has a separate delay, and the delays can be
  different frame-to-frame. We report only the average frame rate.

* Getting the duration of an APNG is surprisingly hard. Most tools don't
  have good support for APNGs since it's a rare and non-standardized
  format. The best we can do is get the frame count using ExifTool and the
  frame rate using ffprobe, then calculate the duration from that.
2021-09-27 05:18:25 -05:00
evazion
f8d52e6758 /status: add more information to /status page.
Add the following:

* Container name, machine name, worker id.
* Container uptime, puma uptime, worker uptime.
* Number of requests processed by current worker.
* ExifTool version.

Also change /status page to show information in tables instead of lists.
2021-09-26 23:11:08 -05:00
evazion
52bf4a3a6b maintenance: break maintenance tasks into individual jobs.
Break the hourly/daily/weekly/monthly maintenance tasks down into
individual delayed jobs. This way if one task fails, it won't prevent
other tasks from running. Also, jobs can be run in parallel, and can be
individually retried if they fail.
2021-09-26 20:38:30 -05:00
evazion
ab3f35580f metadata: move metadata parsing into ExifTool::Metadata.
Move the metadata parsing code from MediaAsset to ExifTool::Metadata so
we can use it outside the context of a MediaAsset, in particular when
dealing with a MediaFile that hasn't been saved to disk yet.
2021-09-26 07:19:36 -05:00
evazion
6f02918676 Merge pull request #4887 from nonamethanks/update-artist-finder
Update artist finder blacklist
2021-09-24 08:54:48 -05:00
nonamethanks
16f76fe396 Update artist finder blacklist 2021-09-24 14:50:19 +02:00
evazion
74b03a7bd0 posts: fix incorrect exif rotation for PNGs.
Fix a bug where where PNG images could be incorrectly detected as
exif-rotated. This would happen when a PNG contained the
IFD0:Orientation flag. It's technically possible for a PNG to contain
this flag, but it's ignored by libvips and by browsers.

post #3762340 (nsfw) is an example of a PNG like this.

The fix is to use `autorot` to let libvips apply the rotation instead of
trying to interpret the exif data ourselves. Note that libvips-8.9 has a
bug where it doesn't strip the orientation flag after applying
`autorot`, which leads to the image being incorrectly rotated a second
time when generating the thumbnail. Use libvips-8.11 instead.
2021-09-23 00:10:00 -05:00
evazion
b378785582 Fix #3692: Rotate pictures based on metadata
Rotate the image based on the EXIF orientation flag when generating
thumbnails and samples.

Also fix the width and height to be calculated correctly for rotated
images. Vips gives us the unrotated width and height of the image; we
have to detect whether the image is rotated and swap the width and
height manually to correct them. For example, if an image with the
"Rotate 90 CW" flag is 100x500 before rotation, then after rotation it's
500x100. This should fix #4883 (Exif rotation breaks Javascript fit-to-window)

We also have to fix it so that regenerating a post updates the width and
height of the post, in the event that it's a rotated image.

Finally we set `image-orientation: from-image;` even though it's
probably not necessary.
2021-09-22 11:12:50 -05:00
evazion
8738d8a645 Remove deletion appeal thread updater.
It was already disabled before, remove it completely now.
2021-09-22 01:57:45 -05:00
evazion
d5981754c4 posts: automatically tag animated_gif & animated_png on tag edit.
Automatically tag animated_gif and animated_png when a post is edited.
Add them back if the user tries to remove them from an animated post,
or remove them if the user tries to add them to a non-animated post.

Before we added these tags at upload time, but it was possible for users
to remove them after upload, or to incorrectly add them to non-animated
posts. They were added at upload time because we couldn't afford to open
the file and parse the metadata on every tag edit. Now that we save the
metadata in the database, we can do this.

This also makes it so you can't tag ugoira on non-ugoira files.

Known bug: it's possible to have an animated GIF where every frame is
identical. Post #3770975 is an example. This will be detected as an
animated GIF even though visually it doesn't appear to be animated.

Fixes #4041: Animated_gif tag not added to preprocessed uploads
2021-09-21 08:26:02 -05:00
evazion
4d0580b160 MediaFile: remove old libvips compatibility code.
Remove code for working with older versions of libvips. This makes
libvips 8.10+ a hard requirement. Older versions were already broken and
failed certain tests in the test suite.
2021-09-21 07:47:48 -05:00
evazion
ae7d964bf1 MediaFile: replace APNGInspector with ExifTool.
Replace our own handwritten APNG parser with ExifTool. This makes
ExifTool a hard requirement for handling APNGs.
2021-09-21 07:47:45 -05:00
evazion
d854bf6b53 BURs: update posts in parallel.
When processing an alias, rename, implication, mass update, or nuke,
update the posts in parallel. This means that if we alias foo to bar,
for example, then we use four processes at once to retag the posts from
foo to bar.

This doesn't mean that if we have two aliases in a BUR, we process both
aliases in parallel. It simply means that when processing an alias, we
update the posts in parallel for that alias.
2021-09-20 01:12:14 -05:00