myspoti
Jetpack Compose로 만든 Spotify 전용 안드로이드 클라이언트
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗neomosh is a video recorder in one standalone HTML file. It makes a true datamosh: it has its own H.264 encoder and decoder. When you pause and resume, the new clip has no keyframe. The P-frames of the new clip move the pixels of the last picture of the previous clip.
The exported file is a valid H.264 (Constrained Baseline) stream. Each conforming player shows the same moshed pictures.
Status: v0.5.0. All phases are done: codec, MP4 export, recorder, history, file source, settings, and Upscale export. neomosh records video only (no audio). See
neomosh-plan-v0.1.0.md.
Put dist/neomosh-v0.5.0.html on a web server with HTTPS (for example GitHub Pages), or open it on localhost. Browsers refuse camera access on plain HTTP. Safari also refuses it on a local file:// page.
Touch Start and give permission to the camera. When the phone has more than one rear camera, chips at the bottom of the view (for example 0.5×, 1×, Tele, or 1, 2, 3) select one, before a clip or while paused. When the camera can zoom, pinch the view with two fingers (also while recording); the chip with the level (for example 2.5×) goes back to 1× when you touch it.
Touch the red button to record. The view shows the decoded output of the encoder.
Touch the button again to pause. The last picture shows above the live camera. Move the Guide slider to change its opacity, and align the next shot.
Touch the red button to resume. The new clip has no keyframe, so its motion moves the old picture. This is the datamosh. The mosh needs movement: if nothing moves, the old picture stays frozen.
Repeat steps 4 and 5 as many times as necessary.
Bloom: while paused, hold the BLOOM button (next to the red button, or the B key). The motion at the end of the last clip repeats, so the picture keeps flowing and smearing in that direction. Release it to end the bloom: it is a clip of its own, with a pause point. The bloomed picture stays, and the next clip moshes on from it.
To use a video file as the source (at the start or at any pause point), touch FILE and select a file. The File slider below the view sets the start point. For an MP4 or MOV file, the app decodes each frame of the file at the speed of the device, not in real time, so no frame is dropped: the view shows the moshed frames as they are made, and the export has the true speed of the file. Other files (for example WebM) play at normal speed while you record. The recording pauses with the file. At the end of the file, the recording pauses. Touch FILE again to select a different file, or CAMERA to go back to the camera. A file is never mirrored. The sound of the file is not recorded. If the camera is not available, the start screen offers Use a video file.
To go back, touch the thumbnail (bottom left) while paused. The History sheet plays the video and shows one card for each pause point. Touch a card, then Revert, to delete all clips after that point and continue from it. Start deletes all clips. New video deletes the video.
Touch Export (top right). For each cut, select Mosh or Clean. Touch Export, then Save Video (iOS) or Download.
Original mode (the default) copies the recorded frames into the file. It is fast and lossless. Upscale mode scales the video to 1080 on the short side (Sharp keeps the blocks, Smooth blurs them) and encodes it again with the H.264 encoder of the browser. Upscale shows only when the browser has an H.264 encoder.
An amber badge shows the count of frames that the encoder dropped. Touch it for help.
Touch the gear (top left).
| Setting | Values | Default | When it can change |
|---|---|---|---|
| Size (short side) | 360, 480, 720, 1080 | 480 | Before the first recorded frame. 720 and 1080 need a fast device |
| Frame rate | 15, 24, 30 | 30 | Before the first recorded frame. A hint shows when the device is too slow for the rate |
| Shape | 1:1, 4:3, 3:2, 16:9; vertical or horizontal | 4:3, from the screen | Before the first recorded frame (bar above the view) |
| Quality (QP) | 16–44 | 30 | While paused. High = coarse blocks; low = clean detail, larger file |
| Search range | ±8, ±16, ±32, ±64 | ±32 | While paused. Larger = longer smears with fast motion, more CPU |
| Motion | Full, Half, Quarter | Quarter | While paused. Full = blocky steps; Quarter = smooth flowing smear |
| Skip bias | 0–100 | 50 | While paused. High = more old pixels stay |
| Heal | Off, Low, High | Low | While paused. Low and High repair bad areas (partial mosh) |
| Denoise | Off, Low, High | Low | While paused. Removes sensor noise before the encoder: faster and smaller with a noisy camera (for example a second rear camera), a little smoother picture |
| Mosh preview | On, Off | On | At any time. Off shows the raw source while recording |
| Mirror front camera | On, Off | On | At any time. Applies to the next clip |
| Theme | Default (green and pink, an animated orb record button), OS (yellow and red), Contrast (white, outlines), Night (soft warm colours) | Default | At any time. Only the look of the app, not the video |
The encoder settings apply to the next clip. Each clip keeps its own look. A revert also restores the settings of that pause point. Default look sets the encoder settings to their defaults. The Info section at the bottom (closed at first) shows the dropped frames, the storage used and free, and how this browser records. When the device is too slow for the selected size and frame rate, it shows a warning; the warning comes only after the first clip, when the speed is measured. Open the page with #debug for the details and the self-test.
| Browser | Status |
|---|---|
| Chrome (Android, desktop) | Tested. Upscale export is available |
| Edge | Same engine as Chrome. Not tested |
| Safari (iOS 16.4 or later, macOS) | Must work. Not tested yet (plan §13.4). Upscale export when Safari has an H.264 VideoEncoder |
| Firefox 132 or later | Must work. Not tested |
The browser must have WebAssembly SIMD for full speed. Without it, the codec uses JavaScript, which is approximately 10 times slower. The page makes no network requests.
For a check of a device, open the page with #debug at the end of the address. The settings sheet then shows Run the self-test. It exports the video, decodes it with the decoder of the browser, and compares each frame with the neomosh decoder. The result must be "PASS. Identical".
The app keeps the video in the browser storage (IndexedDB). When you open the app again, touch Continue last video to continue from the last pause point, or Start new. If the app closed during a recording, it keeps the frames that were stored (all but about the last second) and makes a new pause point.
Requirements: Node.js 20 or later. FFmpeg and ffprobe for the tests.
| Command | Result |
|---|---|
node tools/build.mjs | Makes dist/neomosh-v0.5.0.html and dist/neomosh-bench-v0.5.0.html, and copies the app to index.html (the page for GitHub Pages) |
node tools/build-wasm.mjs | Compiles src/codec/wasm/kernels.c to WebAssembly (needs clang with the wasm32 target). Only after a change to the C code: the compiled module is in the repository |
node tests/run.mjs [filter] | Runs the tests. Output files go to tests/out/ |
node tools/bench.mjs [frames] | Runs the encoder benchmark in Node |
node tools/sample.mjs | Makes sample MP4 files in samples/ for device tests |
node tools/build.mjs.dist/neomosh-bench-v0.5.0.html to the phone (for example with AirDrop or Files), or serve it from a local web server.The page makes no network requests. The encoder p95 time must be below the frame budget: 33.3 ms at 30 fps, 41.7 ms at 24 fps, 66.7 ms at 15 fps.
The tests encode synthetic video, write an Annex B .264 file and an .mp4 file, and decode them with FFmpeg. The FFmpeg output must be byte-identical to the output of our decoder (plan §13.1). The MP4 packets must have the correct times, durations, and sync flags. When Playwright is installed, a test also decodes the MP4 samples with the Chromium WebCodecs decoder and plays the files in a <video> element, and tests operate the built app with a fake camera: record, pause, resume, history, settings, storage full, Original and Upscale export, and the self-test. The mosh test (plan §13.2) makes sure that, after a cut, only the area along the motion path changes.
| Path | Contents |
|---|---|
src/codec/ | H.264 subset: bit I/O, tables, transform, interpolation, motion vector prediction, CAVLC, headers, colour, encoder, decoder |
src/codec/wasm/ | The computation-intensive parts of the codec in C, compiled to WebAssembly with SIMD. The JavaScript functions are the fallback and the reference; the tests prove that both give the same bits |
src/bench/ | Benchmark page and core |
src/app/ | App: user interface (based on neocamera v1.5.0), recorder, workers (capture, encoder, decoder), storage, Upscale export, self-test |
src/mux/ | MP4 muxer and lossless export (remux) |
tools/build.mjs | Inlines all sources into one HTML file for each page |
tests/ | Node tests |
dist/ | Built files |