-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Audio Backend #6824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Audio Backend #6824
Changes from 3 commits
1314938
5f26e48
31b69c1
bb76aff
23c4134
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| # Audio Datatype | ||
|
|
||
| The `Audio` datatype is similar to `Scene` but stores audio-only media (i.e. Audiobooks, music, ASMR, etc). | ||
|
|
||
| ## Scope | ||
|
|
||
| - This ticket adds backend support for Audio Only, future tickets can add the UI elements | ||
| - Audio metadata: | ||
| - Title | ||
| - Artists (string? like director) | ||
| - Date | ||
| - Studio | ||
| - Performers | ||
| - Tags | ||
| - Details | ||
| - Urls | ||
| - Rating | ||
| - Organized | ||
| - O History | ||
| - Play History | ||
| - Studio Code | ||
| - NICE TO HAVES | ||
| - Groups | ||
| - Audio File metadata: | ||
| - duration | ||
| - audio codec | ||
| - OPTIONAL (can be added now or later) | ||
| - channels (mono, stereo, 5.1, 7.1) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would tthis really be needed? Currently scenes have audio and we don't track this at all.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest looking at bitrate again, as this is tracked for scenes (the video portion).
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mostly I was referring to the channels. I think bitrate would be fine. |
||
| - bitrate | ||
| - sample rate | ||
|
|
||
|
|
||
| ## TODO List | ||
|
|
||
| - [ ] `pkg/sqlite/migrations/86_audio.up.sql` | ||
| - Create a migration for the Audio type, very similar to Scene | ||
| - [ ] Duplicate much of `pkg/scene/*` into `pkg/audio/*` | ||
| - Exclude: markers, screenshot, preview, transcode, sprite | ||
| - [ ] Graphql | ||
| - [ ] Copy/modify `graphql/schema/types/scene.graphql` to `graphql/schema/types/audio.graphql` | ||
|
|
||
| ### Last Steps | ||
| - [ ] Delete this file upon completion of the feature | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,300 @@ | ||
| # TODO(audio): update this file | ||
|
|
||
| type AudioFileType { | ||
| size: String | ||
| duration: Float | ||
| video_codec: String | ||
| audio_codec: String | ||
| width: Int | ||
| height: Int | ||
| framerate: Float | ||
| bitrate: Int | ||
| } | ||
|
|
||
| type AudioPathsType { | ||
| screenshot: String # Resolver | ||
| preview: String # Resolver | ||
| stream: String # Resolver | ||
| webp: String # Resolver | ||
| vtt: String # Resolver | ||
| sprite: String # Resolver | ||
| funscript: String # Resolver | ||
| interactive_heatmap: String # Resolver | ||
| caption: String # Resolver | ||
| } | ||
|
|
||
| type AudioMovie { | ||
| movie: Movie! | ||
| audio_index: Int | ||
| } | ||
|
|
||
| type AudioGroup { | ||
| group: Group! | ||
| audio_index: Int | ||
| } | ||
|
|
||
| type VideoCaption { | ||
| language_code: String! | ||
| caption_type: String! | ||
| } | ||
|
|
||
| type Audio { | ||
| id: ID! | ||
| title: String | ||
| code: String | ||
| details: String | ||
| director: String | ||
| url: String @deprecated(reason: "Use urls") | ||
| urls: [String!]! | ||
| date: String | ||
| # rating expressed as 1-100 | ||
| rating100: Int | ||
| organized: Boolean! | ||
| o_counter: Int | ||
| interactive: Boolean! | ||
| interactive_speed: Int | ||
| captions: [VideoCaption!] | ||
| created_at: Time! | ||
| updated_at: Time! | ||
| "The last time play count was updated" | ||
| last_played_at: Time | ||
| "The time index a audio was left at" | ||
| resume_time: Float | ||
| "The total time a audio has spent playing" | ||
| play_duration: Float | ||
| "The number ot times a audio has been played" | ||
| play_count: Int | ||
|
|
||
| "Times a audio was played" | ||
| play_history: [Time!]! | ||
| "Times the o counter was incremented" | ||
| o_history: [Time!]! | ||
|
|
||
| files: [VideoFile!]! | ||
| paths: AudioPathsType! # Resolver | ||
| audio_markers: [AudioMarker!]! | ||
| galleries: [Gallery!]! | ||
| studio: Studio | ||
| groups: [AudioGroup!]! | ||
| movies: [AudioMovie!]! @deprecated(reason: "Use groups") | ||
| tags: [Tag!]! | ||
| performers: [Performer!]! | ||
| stash_ids: [StashID!]! | ||
|
|
||
| custom_fields: Map! | ||
|
|
||
| "Return valid stream paths" | ||
| audioStreams: [AudioStreamEndpoint!]! | ||
| } | ||
|
|
||
| input AudioMovieInput { | ||
| movie_id: ID! | ||
| audio_index: Int | ||
| } | ||
|
|
||
| input AudioGroupInput { | ||
| group_id: ID! | ||
| audio_index: Int | ||
| } | ||
|
|
||
| input AudioCreateInput { | ||
| title: String | ||
| code: String | ||
| details: String | ||
| director: String | ||
| url: String @deprecated(reason: "Use urls") | ||
| urls: [String!] | ||
| date: String | ||
| # rating expressed as 1-100 | ||
| rating100: Int | ||
| organized: Boolean | ||
| studio_id: ID | ||
| gallery_ids: [ID!] | ||
| performer_ids: [ID!] | ||
| groups: [AudioGroupInput!] | ||
| movies: [AudioMovieInput!] @deprecated(reason: "Use groups") | ||
| tag_ids: [ID!] | ||
| "This should be a URL or a base64 encoded data URL" | ||
| cover_image: String | ||
| stash_ids: [StashIDInput!] | ||
|
|
||
| """ | ||
| The first id will be assigned as primary. | ||
| Files will be reassigned from existing audios if applicable. | ||
| Files must not already be primary for another audio. | ||
| """ | ||
| file_ids: [ID!] | ||
|
|
||
| custom_fields: Map | ||
| } | ||
|
|
||
| input AudioUpdateInput { | ||
| clientMutationId: String | ||
| id: ID! | ||
| title: String | ||
| code: String | ||
| details: String | ||
| director: String | ||
| url: String @deprecated(reason: "Use urls") | ||
| urls: [String!] | ||
| date: String | ||
| # rating expressed as 1-100 | ||
| rating100: Int | ||
| o_counter: Int | ||
| @deprecated(reason: "Unsupported - Use audioIncrementO/audioDecrementO") | ||
| organized: Boolean | ||
| studio_id: ID | ||
| gallery_ids: [ID!] | ||
| performer_ids: [ID!] | ||
| groups: [AudioGroupInput!] | ||
| movies: [AudioMovieInput!] @deprecated(reason: "Use groups") | ||
| tag_ids: [ID!] | ||
| "This should be a URL or a base64 encoded data URL" | ||
| cover_image: String | ||
| stash_ids: [StashIDInput!] | ||
|
|
||
| "The time index a audio was left at" | ||
| resume_time: Float | ||
| "The total time a audio has spent playing" | ||
| play_duration: Float | ||
| "The number ot times a audio has been played" | ||
| play_count: Int | ||
| @deprecated( | ||
| reason: "Unsupported - Use audioIncrementPlayCount/audioDecrementPlayCount" | ||
| ) | ||
|
|
||
| primary_file_id: ID | ||
|
|
||
| custom_fields: CustomFieldsInput | ||
| } | ||
|
|
||
| enum BulkUpdateIdMode { | ||
| SET | ||
| ADD | ||
| REMOVE | ||
| } | ||
|
|
||
| input BulkUpdateIds { | ||
| ids: [ID!] | ||
| mode: BulkUpdateIdMode! | ||
| } | ||
|
|
||
| input BulkAudioUpdateInput { | ||
| clientMutationId: String | ||
| ids: [ID!] | ||
| title: String | ||
| code: String | ||
| details: String | ||
| director: String | ||
| url: String @deprecated(reason: "Use urls") | ||
| urls: BulkUpdateStrings | ||
| date: String | ||
| # rating expressed as 1-100 | ||
| rating100: Int | ||
| organized: Boolean | ||
| studio_id: ID | ||
| gallery_ids: BulkUpdateIds | ||
| performer_ids: BulkUpdateIds | ||
| tag_ids: BulkUpdateIds | ||
| group_ids: BulkUpdateIds | ||
| movie_ids: BulkUpdateIds @deprecated(reason: "Use group_ids") | ||
|
|
||
| custom_fields: CustomFieldsInput | ||
| } | ||
|
|
||
| input AudioDestroyInput { | ||
| id: ID! | ||
| delete_file: Boolean | ||
| delete_generated: Boolean | ||
| "If true, delete the file entry from the database if the file is not assigned to any other objects" | ||
| destroy_file_entry: Boolean | ||
| } | ||
|
|
||
| input AudiosDestroyInput { | ||
| ids: [ID!]! | ||
| delete_file: Boolean | ||
| delete_generated: Boolean | ||
| "If true, delete the file entry from the database if the file is not assigned to any other objects" | ||
| destroy_file_entry: Boolean | ||
| } | ||
|
|
||
| type FindAudiosResultType { | ||
| count: Int! | ||
| "Total duration in seconds" | ||
| duration: Float! | ||
| "Total file size in bytes" | ||
| filesize: Float! | ||
| audios: [Audio!]! | ||
| } | ||
|
|
||
| input AudioParserInput { | ||
| ignoreWords: [String!] | ||
| whitespaceCharacters: String | ||
| capitalizeTitle: Boolean | ||
| ignoreOrganized: Boolean | ||
| } | ||
|
|
||
| type AudioMovieID { | ||
| movie_id: ID! | ||
| audio_index: String | ||
| } | ||
|
|
||
| type AudioParserResult { | ||
| audio: Audio! | ||
| title: String | ||
| code: String | ||
| details: String | ||
| director: String | ||
| url: String | ||
| date: String | ||
| # rating expressed as 1-5 | ||
| rating: Int @deprecated(reason: "Use 1-100 range with rating100") | ||
| # rating expressed as 1-100 | ||
| rating100: Int | ||
| studio_id: ID | ||
| gallery_ids: [ID!] | ||
| performer_ids: [ID!] | ||
| movies: [AudioMovieID!] | ||
| tag_ids: [ID!] | ||
| } | ||
|
|
||
| type AudioParserResultType { | ||
| count: Int! | ||
| results: [AudioParserResult!]! | ||
| } | ||
|
|
||
| input AudioHashInput { | ||
| checksum: String | ||
| oshash: String | ||
| } | ||
|
|
||
| type AudioStreamEndpoint { | ||
| url: String! | ||
| mime_type: String | ||
| label: String | ||
| } | ||
|
|
||
| input AssignAudioFileInput { | ||
| audio_id: ID! | ||
| file_id: ID! | ||
| } | ||
|
|
||
| input AudioMergeInput { | ||
| """ | ||
| If destination audio has no files, then the primary file of the | ||
| first source audio will be assigned as primary | ||
| """ | ||
| source: [ID!]! | ||
| destination: ID! | ||
| # values defined here will override values in the destination | ||
| values: AudioUpdateInput | ||
|
|
||
| # if true, the source history will be combined with the destination | ||
| play_history: Boolean | ||
| o_history: Boolean | ||
| } | ||
|
|
||
| type HistoryMutationResult { | ||
| count: Int! | ||
| history: [Time!]! | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| # TODO(audio): add AudioFilterType | ||
|
|
||
| enum SortDirectionEnum { | ||
| ASC | ||
| DESC | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Gykes / @WithoutPants : You can see a limited scope here. The database design
pkg/sqlite/migrations/86_audio.up.sqlshows the extent of the change.If I get a thumbs up, then I will start work. If you want to increase/reduce scope, or to wait for any other PRs, let me know here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should nail down where this is planning on going. XXX vs non XXX
I prefer the former as that's what this app is kind of aimed at. If we do XXX then I believe that having Performer and Artist in the audio metadata would be confusing and would conflict. I say we just roll with what we currently have and not add Artists.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am okay with all suggested changes.
Still waiting for some confirmation that the scope will be accepted before investing time into this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Gykes if you feel comfortable giving the thumbs up on this, then I can go ahead.
For all of your suggestions, I placed a 👍 to indicate that I agree and will make the change once I start working.
I will be using this for SFW, but don't mind building it for NSFW. I will adopt all your suggestions (except the rating100, see PR comment to discuss)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the fact that the main dev has said it's okay in previous comments and casually in passing then I'm okay giving the thumbs up. I can test/review as you go or in chunks, whatever you are more comfortable doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Gykes this will be a large PR, if you want to provide reviews as commits come, or wait till the end; whatever you think is best to ensure this gets merged. I am also open to excluding/deferring sections to reduce the PR size
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just give me a ping when you feel it's ready for a review/test